https 替换

This commit is contained in:
2025-12-27 17:34:19 +08:00
parent 55801fa0ec
commit 0fb7a4ffb2
18 changed files with 233 additions and 293 deletions

View File

@@ -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),

View File

@@ -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

View File

@@ -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();
// 构造TbSysUserDTOstatus设为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 {

View File

@@ -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