https 替换
This commit is contained in:
@@ -285,12 +285,7 @@ INSERT INTO sys.tb_sys_view (
|
||||
'route', NULL, 'workcase', NULL, 162, '工单操作日志', 'system', now(), false),
|
||||
|
||||
('VIEW-W109', 'view_workcase_admin_log_system', '系统日志', 'view_workcase_admin_log', '/admin/log/system', 'admin/log/systemLog/SystemLogView.vue', 'Settings', 1,
|
||||
'route', NULL, 'workcase', NULL, 163, '系统运行日志', 'system', now(), false),
|
||||
|
||||
-- Jitsi视频会议独立页面(支持URL参数token认证,用于小程序和外部链接访问)
|
||||
('VIEW-W003', 'view_workcase_jitsi_meeting', 'Jitsi视频会议', NULL, '/meeting', 'public/JitsiMeeting/JitsiMeetingView.vue', 'Video', 1,
|
||||
'route', NULL, 'workcase', 'BlankLayout', 25, 'Jitsi视频会议独立页面,支持URL参数token认证', 'system', now(), false);
|
||||
|
||||
'route', NULL, 'workcase', NULL, 163, '系统运行日志', 'system', now(), false);
|
||||
-- =============================
|
||||
-- 6. 角色权限关联(超级管理员拥有所有权限)
|
||||
-- =============================
|
||||
@@ -432,9 +427,6 @@ INSERT INTO sys.tb_sys_view_permission (
|
||||
('VP-W108', 'view_workcase_admin_log_workcase', 'perm_workcase_log', 'system', NULL, now(), false),
|
||||
('VP-W109', 'view_workcase_admin_log_system', 'perm_workcase_log', 'system', NULL, now(), false),
|
||||
|
||||
-- Jitsi视频会议页面关联会议权限
|
||||
('VP-W003', 'view_workcase_jitsi_meeting', 'perm_meeting_join', 'system', NULL, now(), false);
|
||||
|
||||
-- -- 用户管理视图关联用户权限(已注释,因为view_user被注释掉了)
|
||||
-- -- ('VP-0001', 'view_user', 'perm_user_view', 'system', NULL, now(), false),
|
||||
-- -- ('VP-0002', 'view_user', 'perm_user_create', 'system', NULL, now(), false),
|
||||
|
||||
@@ -105,15 +105,15 @@ services:
|
||||
networks:
|
||||
- urban-lifeline
|
||||
ports:
|
||||
- "8280:80" # 保留原 HTTP 端口
|
||||
- "8443:443" # 保留原 HTTPS 端口(仅保留映射,实际禁用 HTTPS)
|
||||
- "8280:80" # HTTP 端口(通过 Nginx 反向代理)
|
||||
- "8443:443" # HTTPS 端口
|
||||
environment:
|
||||
# 基础配置(局域网访问)
|
||||
# 基础配置(Jitsi容器使用HTTP,由Nginx提供HTTPS)
|
||||
TZ: Asia/Shanghai
|
||||
# 关键:使用 http:// 协议的完整 URL
|
||||
PUBLIC_URL: 192.168.0.253:8280
|
||||
|
||||
# 关键:禁用 HTTPS,让容器生成 ws:// 而不是 wss://
|
||||
# PUBLIC_URL设置为独立子域名
|
||||
PUBLIC_URL: https://org.xyzh.yslg.jitsi
|
||||
|
||||
# 禁用容器内部HTTPS(由Nginx统一处理HTTPS)
|
||||
ENABLE_HTTPS: 0
|
||||
ENABLE_HTTP_REDIRECT: 0
|
||||
DISABLE_HTTPS: 1
|
||||
@@ -142,7 +142,7 @@ services:
|
||||
JWT_APP_SECRET: urbanLifeline-jitsi-secret-key-2025-production-safe-hs256
|
||||
JWT_ACCEPTED_ISSUERS: urbanLifeline
|
||||
JWT_ACCEPTED_AUDIENCES: jitsi
|
||||
JWT_ASAP_KEYSERVER: https://192.168.0.253:8280/
|
||||
JWT_ASAP_KEYSERVER: https://org.xyzh.yslg.jitsi/
|
||||
JWT_ALLOW_EMPTY: 0
|
||||
JWT_AUTH_TYPE: token
|
||||
JWT_TOKEN_AUTH_MODULE: token_verification
|
||||
@@ -154,9 +154,9 @@ services:
|
||||
ENABLE_XMPP_WEBSOCKET: 1
|
||||
ENABLE_SCTP: 1
|
||||
|
||||
# 日志/HTTPS 配置
|
||||
# 不使用Let's Encrypt(使用mkcert证书)
|
||||
ENABLE_LETSENCRYPT: 0
|
||||
LETSENCRYPT_DOMAIN: 192.168.0.253
|
||||
LETSENCRYPT_DOMAIN: org.xyzh.yslg.jitsi
|
||||
|
||||
volumes:
|
||||
- ../../../.data/docker/jitsi/web:/config
|
||||
@@ -217,7 +217,7 @@ services:
|
||||
LOG_LEVEL: info
|
||||
|
||||
# 公共URL(局域网访问)
|
||||
PUBLIC_URL: 192.168.0.253:8280
|
||||
PUBLIC_URL: https://org.xyzh.yslg.jitsi
|
||||
|
||||
volumes:
|
||||
- ../../../.data/docker/jitsi/prosody/config:/config
|
||||
|
||||
@@ -5,9 +5,11 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.xyzh.api.auth.service.AuthService;
|
||||
import org.xyzh.api.system.service.SysUserService;
|
||||
import org.xyzh.api.system.service.ModulePermissionService;
|
||||
import org.xyzh.api.system.service.GuestService;
|
||||
import org.xyzh.api.system.vo.SysUserVO;
|
||||
import org.xyzh.api.system.vo.PermissionVO;
|
||||
import org.xyzh.api.system.vo.UserDeptRoleVO;
|
||||
import org.xyzh.common.dto.sys.TbGuestDTO;
|
||||
import org.xyzh.auth.enums.UserStatus;
|
||||
import org.xyzh.auth.strategy.LoginStrategyFactory;
|
||||
import org.xyzh.auth.strategy.LoginStrategy;
|
||||
@@ -64,6 +66,9 @@ public class AuthServiceImpl implements AuthService{
|
||||
@DubboReference(version = "1.0.0", group = "system", timeout = 5000, check = false, retries = 0)
|
||||
private ModulePermissionService modulePermissionService;
|
||||
|
||||
@DubboReference(version = "1.0.0", group = "system", timeout = 5000, check = false, retries = 0)
|
||||
private GuestService guestService;
|
||||
|
||||
@Autowired
|
||||
private LoginStrategyFactory loginStrategyFactory;
|
||||
|
||||
@@ -412,63 +417,164 @@ public class AuthServiceImpl implements AuthService{
|
||||
if (token == null || token.trim().isEmpty()) {
|
||||
return ResultDomain.failure("Token不能为空");
|
||||
}
|
||||
|
||||
|
||||
// 1. 验证当前Token是否有效
|
||||
if (jwtTokenUtil.isTokenExpired(token)) {
|
||||
return ResultDomain.failure("Token已过期");
|
||||
}
|
||||
|
||||
// 2. 从Redis获取登录信息
|
||||
|
||||
// 2. 从JWT中提取用户ID和登录类型
|
||||
String userId = jwtTokenUtil.getUserIdFromToken(token);
|
||||
String loginType = jwtTokenUtil.getClaimFromToken(token, claims -> claims.get("loginType", String.class));
|
||||
|
||||
if (userId == null || userId.trim().isEmpty()) {
|
||||
return ResultDomain.failure("Token信息不完整");
|
||||
}
|
||||
|
||||
logger.info("Token刷新请求:userId={}, loginType={}", userId, loginType);
|
||||
|
||||
// 3. 尝试从Redis获取登录信息(优先使用缓存)
|
||||
String loginKey = "login:token:" + token;
|
||||
String loginJson = redisService.get(loginKey, String.class);
|
||||
if (loginJson == null) {
|
||||
return ResultDomain.failure("登录信息已失效");
|
||||
LoginDomain oldLoginDomain = null;
|
||||
|
||||
if (loginJson != null) {
|
||||
oldLoginDomain = JSON.parseObject(loginJson, LoginDomain.class);
|
||||
if (loginType == null && oldLoginDomain != null) {
|
||||
loginType = oldLoginDomain.getLoginType();
|
||||
}
|
||||
}
|
||||
|
||||
LoginDomain oldLoginDomain = JSON.parseObject(loginJson, LoginDomain.class);
|
||||
|
||||
// 3. 获取用户最新信息
|
||||
ResultDomain<SysUserVO> userInfoResult = userService.getUserInfo(oldLoginDomain.getUser().getUserId());
|
||||
if (!userInfoResult.getSuccess() || userInfoResult.getData() == null) {
|
||||
return ResultDomain.failure("获取用户信息失败");
|
||||
|
||||
// 4. 根据登录类型获取最新用户信息
|
||||
LoginDomain newLoginDomain;
|
||||
|
||||
if ("wechat_miniprogram".equals(loginType)) {
|
||||
// 来客(小程序)用户:从guest表获取信息
|
||||
TbGuestDTO guestDTO = new TbGuestDTO();
|
||||
guestDTO.setUserId(userId);
|
||||
ResultDomain<TbGuestDTO> guestResult = guestService.selectGuestOne(guestDTO);
|
||||
if (!guestResult.getSuccess() || guestResult.getData() == null) {
|
||||
return ResultDomain.failure("获取来客信息失败");
|
||||
}
|
||||
|
||||
TbGuestDTO guest = guestResult.getData();
|
||||
newLoginDomain = buildGuestLoginDomain(guest, loginType);
|
||||
|
||||
} else {
|
||||
// 普通用户:从sys_user表获取信息
|
||||
ResultDomain<SysUserVO> userInfoResult = userService.getUserInfo(userId);
|
||||
if (!userInfoResult.getSuccess() || userInfoResult.getData() == null) {
|
||||
return ResultDomain.failure("获取用户信息失败");
|
||||
}
|
||||
|
||||
SysUserVO userInfo = userInfoResult.getData();
|
||||
String effectiveLoginType = (loginType != null) ? loginType : "password";
|
||||
newLoginDomain = buildLoginDomain(userInfo, effectiveLoginType, clientIp);
|
||||
}
|
||||
|
||||
SysUserVO userInfo = userInfoResult.getData();
|
||||
|
||||
// 4. 重新构建LoginDomain
|
||||
LoginDomain newLoginDomain = buildLoginDomain(userInfo, oldLoginDomain.getLoginType(), clientIp);
|
||||
|
||||
if (newLoginDomain == null) {
|
||||
return ResultDomain.failure("构建登录信息失败");
|
||||
}
|
||||
|
||||
|
||||
// 5. 生成新Token
|
||||
String newToken = jwtTokenUtil.generateToken(newLoginDomain);
|
||||
newLoginDomain.setToken(newToken);
|
||||
|
||||
// 6. 删除旧的Token信息
|
||||
redisService.delete(loginKey);
|
||||
|
||||
|
||||
// 6. 删除旧的Token信息(如果存在)
|
||||
if (loginJson != null) {
|
||||
redisService.delete(loginKey);
|
||||
}
|
||||
|
||||
// 7. 存储新的登录信息
|
||||
String newLoginKey = "login:token:" + newToken;
|
||||
redisService.set(newLoginKey, JSON.toJSONString(newLoginDomain), 24, TimeUnit.HOURS);
|
||||
|
||||
|
||||
// 8. 更新用户登录状态
|
||||
String userLoginKey = "login:user:" + userInfo.getUserId();
|
||||
String userLoginKey = "login:user:" + userId;
|
||||
redisService.set(userLoginKey, newToken, 24, TimeUnit.HOURS);
|
||||
|
||||
logger.info("Token刷新成功:userId={}, oldToken={}, newToken={}",
|
||||
userInfo.getUserId(),
|
||||
|
||||
logger.info("Token刷新成功:userId={}, loginType={}, oldToken={}, newToken={}",
|
||||
userId,
|
||||
loginType,
|
||||
token.substring(0, Math.min(10, token.length())) + "...",
|
||||
newToken.substring(0, Math.min(10, newToken.length())) + "...");
|
||||
|
||||
|
||||
return ResultDomain.success("Token刷新成功", newLoginDomain);
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("Token刷新失败", e);
|
||||
return ResultDomain.failure("Token刷新失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从来客信息构造LoginDomain(用于token刷新)
|
||||
*/
|
||||
private LoginDomain buildGuestLoginDomain(TbGuestDTO guest, String loginType) {
|
||||
try {
|
||||
LoginDomain loginDomain = new LoginDomain();
|
||||
|
||||
// 构造TbSysUserDTO,status设为guest
|
||||
TbSysUserDTO userDTO = new TbSysUserDTO();
|
||||
userDTO.setUserId(guest.getUserId());
|
||||
userDTO.setPhone(guest.getPhone());
|
||||
userDTO.setEmail(guest.getEmail());
|
||||
userDTO.setWechatId(guest.getWechatId());
|
||||
userDTO.setStatus("guest"); // 来客特殊状态
|
||||
loginDomain.setUser(userDTO);
|
||||
|
||||
// 构造TbSysUserInfoDTO
|
||||
TbSysUserInfoDTO userInfoDTO = new TbSysUserInfoDTO();
|
||||
userInfoDTO.setUserId(guest.getUserId());
|
||||
userInfoDTO.setUsername(guest.getName() != null ? guest.getName() : "来客");
|
||||
loginDomain.setUserInfo(userInfoDTO);
|
||||
|
||||
// 设置角色信息
|
||||
List<TbSysUserRoleDTO> userRoles = new ArrayList<>();
|
||||
TbSysUserRoleDTO userRole = new TbSysUserRoleDTO();
|
||||
userRole.setUserId(guest.getUserId());
|
||||
userRole.setRoleId("role_guest");
|
||||
userRole.setDeptId("dept_root");
|
||||
userRoles.add(userRole);
|
||||
loginDomain.setUserRoles(userRoles);
|
||||
|
||||
// 获取用户权限信息
|
||||
List<TbSysPermissionDTO> userPermissions = new ArrayList<>();
|
||||
List<TbSysViewDTO> userViews = new ArrayList<>();
|
||||
|
||||
ResultDomain<PermissionVO> permissionsResult = modulePermissionService.getUserPermissions(guest.getUserId());
|
||||
if (permissionsResult.getSuccess() && permissionsResult.getDataList() != null) {
|
||||
for (PermissionVO permission : permissionsResult.getDataList()) {
|
||||
if (permission.getPermissionId() != null) {
|
||||
TbSysPermissionDTO permissionDTO = PermissionVO.toPermissionDTO(permission);
|
||||
if (permissionDTO != null) {
|
||||
userPermissions.add(permissionDTO);
|
||||
}
|
||||
}
|
||||
if (permission.getViewId() != null) {
|
||||
TbSysViewDTO viewDTO = PermissionVO.toViewDTO(permission);
|
||||
if (viewDTO != null) {
|
||||
userViews.add(viewDTO);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
loginDomain.setUserPermissions(userPermissions);
|
||||
loginDomain.setUserViews(userViews);
|
||||
|
||||
// 设置登录类型
|
||||
loginDomain.setLoginType(loginType != null ? loginType : "wechat_miniprogram");
|
||||
|
||||
logger.info("构建来客LoginDomain成功:userId={}, name={}", guest.getUserId(), guest.getName());
|
||||
|
||||
return loginDomain;
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("构建来客LoginDomain失败:userId={}", guest.getUserId(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultDomain<LoginDomain> logout(String token) {
|
||||
try {
|
||||
|
||||
@@ -104,8 +104,8 @@ jitsi:
|
||||
# 注意:HS256算法要求密钥长度至少32字节(256 bits)
|
||||
secret: urbanLifeline-jitsi-secret-key-2025-production-safe-hs256
|
||||
server:
|
||||
# Jitsi Meet服务器地址(Docker部署在本地8280端口)
|
||||
url: http://localhost:8280
|
||||
# Jitsi Meet服务器地址(独立子域名)
|
||||
url: https://org.xyzh.yslg.jitsi
|
||||
token:
|
||||
# JWT Token有效期(毫秒)- 默认2小时
|
||||
expiration: 7200000
|
||||
Reference in New Issue
Block a user