| | |
| | | package com.ruoyi.web.controller.webSocket; |
| | | |
| | | import com.ruoyi.common.constant.Constants; |
| | | import com.ruoyi.common.core.domain.model.LoginUserApplet; |
| | | import com.ruoyi.common.core.redis.RedisCache; |
| | | import com.ruoyi.system.model.TAppUser; |
| | | import com.ruoyi.system.service.TAppUserService; |
| | | import io.jsonwebtoken.Claims; |
| | | import io.jsonwebtoken.Jwts; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.beans.factory.annotation.Value; |
| | | import org.springframework.stereotype.Component; |
| | | import org.springframework.util.StringUtils; |
| | | |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * WebSocket认证处理器 |
| | | * 处理WebSocket连接的用户认证逻辑 |
| | | */ |
| | | @Component |
| | | @Slf4j |
| | | public class WebSocketAuthHandler { |
| | | |
| | | |
| | | @Autowired |
| | | private RedisCache redisCache; |
| | | |
| | | // 令牌秘钥 |
| | | @Value("${token.secret}") |
| | | private String secret; |
| | | |
| | | /** |
| | | * 验证用户认证信息 |
| | | * @param appUserId 用户ID |
| | | * @param token 认证令牌(可选) |
| | | * @return 认证结果 |
| | | */ |
| | | public AuthResult authenticateUser(String appUserId, String token) { |
| | | try { |
| | | if (appUserId == null || appUserId.trim().isEmpty()) { |
| | | return AuthResult.failure("用户ID不能为空"); |
| | | } |
| | | |
| | | |
| | | return AuthResult.success(); |
| | | } catch (Exception e) { |
| | | log.error("用户认证失败,用户ID: {}, 错误: {}", appUserId, e.getMessage(), e); |
| | | return AuthResult.failure("认证过程中发生错误: " + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 验证token |
| | | * @param appUserId 用户ID |
| | | * @param token 令牌 |
| | | * @return 是否有效 |
| | | */ |
| | | private boolean validateToken(String appUserId, String token) { |
| | | try { |
| | | if (!StringUtils.hasText(token)) { |
| | | log.debug("用户 {} 未提供token,跳过token验证", appUserId); |
| | | return true; // 如果没有提供token,允许通过(可以根据业务需求调整) |
| | | } |
| | | |
| | | // 移除Bearer前缀 |
| | | if (token.startsWith(Constants.TOKEN_PREFIX)) { |
| | | token = token.replace(Constants.TOKEN_PREFIX, ""); |
| | | } |
| | | |
| | | // 解析JWT token |
| | | Claims claims = parseToken(token); |
| | | if (claims == null) { |
| | | log.warn("用户 {} 的token解析失败", appUserId); |
| | | return false; |
| | | } |
| | | |
| | | // 从token中获取用户标识 |
| | | String uuid = (String) claims.get(Constants.LOGIN_USER_APPLET_KEY); |
| | | if (!StringUtils.hasText(uuid)) { |
| | | log.warn("用户 {} 的token中未找到用户标识", appUserId); |
| | | return false; |
| | | } |
| | | |
| | | // 从Redis中获取用户登录信息 |
| | | String userKey = getTokenKey(uuid); |
| | | LoginUserApplet loginUser = redisCache.getCacheObject(userKey); |
| | | |
| | | if (loginUser == null) { |
| | | log.warn("用户 {} 的登录信息已过期或不存在", appUserId); |
| | | return false; |
| | | } |
| | | |
| | | // 验证用户ID是否匹配 |
| | | if (!appUserId.equals(loginUser.getUserId())) { |
| | | log.warn("用户 {} 的token与提供的用户ID不匹配", appUserId); |
| | | return false; |
| | | } |
| | | |
| | | // 验证token是否过期 |
| | | long currentTime = System.currentTimeMillis(); |
| | | if (loginUser.getExpireTime() != null && loginUser.getExpireTime() < currentTime) { |
| | | log.warn("用户 {} 的token已过期", appUserId); |
| | | return false; |
| | | } |
| | | |
| | | log.debug("用户 {} 的token验证成功", appUserId); |
| | | return true; |
| | | |
| | | } catch (Exception e) { |
| | | log.error("验证用户 {} 的token时发生错误: {}", appUserId, e.getMessage(), e); |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 解析JWT token |
| | | * @param token JWT token |
| | | * @return Claims对象 |
| | | */ |
| | | private Claims parseToken(String token) { |
| | | try { |
| | | return Jwts.parser() |
| | | .setSigningKey(secret) |
| | | .parseClaimsJws(token) |
| | | .getBody(); |
| | | } catch (Exception e) { |
| | | log.error("解析token失败: {}", e.getMessage()); |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 获取token在Redis中的key |
| | | * @param uuid 用户唯一标识 |
| | | * @return Redis key |
| | | */ |
| | | private String getTokenKey(String uuid) { |
| | | return com.ruoyi.common.constant.CacheConstants.LOGIN_TOKEN_KEY + uuid; |
| | | } |
| | | |
| | | /** |
| | | * 认证结果类 |
| | | */ |
| | | public static class AuthResult { |
| | | private final boolean success; |
| | | private final String message; |
| | | private final TAppUser appUser; |
| | | |
| | | private AuthResult(boolean success, String message, TAppUser appUser) { |
| | | this.success = success; |
| | | this.message = message; |
| | | this.appUser = appUser; |
| | | } |
| | | |
| | | public static AuthResult success(TAppUser appUser) { |
| | | return new AuthResult(true, "认证成功", appUser); |
| | | } |
| | | |
| | | public static AuthResult failure(String message) { |
| | | return new AuthResult(false, message, null); |
| | | } |
| | | |
| | | public boolean isSuccess() { |
| | | return success; |
| | | } |
| | | |
| | | public String getMessage() { |
| | | return message; |
| | | } |
| | | |
| | | public TAppUser getAppUser() { |
| | | return appUser; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 从认证消息中提取用户信息 |
| | | * @param messageObj 消息对象 |
| | | * @return 用户认证信息 |
| | | */ |
| | | public UserAuthInfo extractAuthInfo(Map<String, Object> messageObj) { |
| | | String appUserId = (String) messageObj.get("appUserId"); |
| | | String token = (String) messageObj.get("token"); |
| | | String deviceId = (String) messageObj.get("deviceId"); |
| | | String deviceType = (String) messageObj.get("deviceType"); |
| | | |
| | | return new UserAuthInfo(appUserId, token, deviceId, deviceType); |
| | | } |
| | | |
| | | /** |
| | | * 用户认证信息类 |
| | | */ |
| | | public static class UserAuthInfo { |
| | | private final String appUserId; |
| | | private final String token; |
| | | private final String deviceId; |
| | | private final String deviceType; |
| | | |
| | | public UserAuthInfo(String appUserId, String token, String deviceId, String deviceType) { |
| | | this.appUserId = appUserId; |
| | | this.token = token; |
| | | this.deviceId = deviceId; |
| | | this.deviceType = deviceType; |
| | | } |
| | | |
| | | public String getAppUserId() { |
| | | return appUserId; |
| | | } |
| | | |
| | | public String getToken() { |
| | | return token; |
| | | } |
| | | |
| | | public String getDeviceId() { |
| | | return deviceId; |
| | | } |
| | | |
| | | public String getDeviceType() { |
| | | return deviceType; |
| | | } |
| | | } |
| | | } |
| | | //package com.ruoyi.web.controller.webSocket; |
| | | // |
| | | //import com.ruoyi.common.constant.Constants; |
| | | //import com.ruoyi.common.core.domain.model.LoginUserApplet; |
| | | //import com.ruoyi.common.core.redis.RedisCache; |
| | | //import io.jsonwebtoken.Claims; |
| | | //import io.jsonwebtoken.Jwts; |
| | | //import lombok.extern.slf4j.Slf4j; |
| | | //import org.springframework.beans.factory.annotation.Autowired; |
| | | //import org.springframework.beans.factory.annotation.Value; |
| | | //import org.springframework.stereotype.Component; |
| | | //import org.springframework.util.StringUtils; |
| | | // |
| | | //import java.util.Map; |
| | | // |
| | | ///** |
| | | // * WebSocket认证处理器 |
| | | // * 处理WebSocket连接的用户认证逻辑 |
| | | // */ |
| | | //@Component |
| | | //@Slf4j |
| | | //public class WebSocketAuthHandler { |
| | | // |
| | | // |
| | | // @Autowired |
| | | // private RedisCache redisCache; |
| | | // |
| | | // // 令牌秘钥 |
| | | // @Value("${token.secret}") |
| | | // private String secret; |
| | | // |
| | | // /** |
| | | // * 验证用户认证信息 |
| | | // * @param appUserId 用户ID |
| | | // * @param token 认证令牌(可选) |
| | | // * @return 认证结果 |
| | | // */ |
| | | // public AuthResult authenticateUser(String appUserId, String token) { |
| | | // try { |
| | | // if (appUserId == null || appUserId.trim().isEmpty()) { |
| | | // return AuthResult.failure("用户ID不能为空"); |
| | | // } |
| | | // |
| | | // |
| | | // return AuthResult.success(); |
| | | // } catch (Exception e) { |
| | | // log.error("用户认证失败,用户ID: {}, 错误: {}", appUserId, e.getMessage(), e); |
| | | // return AuthResult.failure("认证过程中发生错误: " + e.getMessage()); |
| | | // } |
| | | // } |
| | | // |
| | | // /** |
| | | // * 验证token |
| | | // * @param appUserId 用户ID |
| | | // * @param token 令牌 |
| | | // * @return 是否有效 |
| | | // */ |
| | | // private boolean validateToken(String appUserId, String token) { |
| | | // try { |
| | | // if (!StringUtils.hasText(token)) { |
| | | // log.debug("用户 {} 未提供token,跳过token验证", appUserId); |
| | | // return true; // 如果没有提供token,允许通过(可以根据业务需求调整) |
| | | // } |
| | | // |
| | | // // 移除Bearer前缀 |
| | | // if (token.startsWith(Constants.TOKEN_PREFIX)) { |
| | | // token = token.replace(Constants.TOKEN_PREFIX, ""); |
| | | // } |
| | | // |
| | | // // 解析JWT token |
| | | // Claims claims = parseToken(token); |
| | | // if (claims == null) { |
| | | // log.warn("用户 {} 的token解析失败", appUserId); |
| | | // return false; |
| | | // } |
| | | // |
| | | // // 从token中获取用户标识 |
| | | // String uuid = (String) claims.get(Constants.LOGIN_USER_APPLET_KEY); |
| | | // if (!StringUtils.hasText(uuid)) { |
| | | // log.warn("用户 {} 的token中未找到用户标识", appUserId); |
| | | // return false; |
| | | // } |
| | | // |
| | | // // 从Redis中获取用户登录信息 |
| | | // String userKey = getTokenKey(uuid); |
| | | // LoginUserApplet loginUser = redisCache.getCacheObject(userKey); |
| | | // |
| | | // if (loginUser == null) { |
| | | // log.warn("用户 {} 的登录信息已过期或不存在", appUserId); |
| | | // return false; |
| | | // } |
| | | // |
| | | // // 验证用户ID是否匹配 |
| | | // if (!appUserId.equals(loginUser.getUserId())) { |
| | | // log.warn("用户 {} 的token与提供的用户ID不匹配", appUserId); |
| | | // return false; |
| | | // } |
| | | // |
| | | // // 验证token是否过期 |
| | | // long currentTime = System.currentTimeMillis(); |
| | | // if (loginUser.getExpireTime() != null && loginUser.getExpireTime() < currentTime) { |
| | | // log.warn("用户 {} 的token已过期", appUserId); |
| | | // return false; |
| | | // } |
| | | // |
| | | // log.debug("用户 {} 的token验证成功", appUserId); |
| | | // return true; |
| | | // |
| | | // } catch (Exception e) { |
| | | // log.error("验证用户 {} 的token时发生错误: {}", appUserId, e.getMessage(), e); |
| | | // return false; |
| | | // } |
| | | // } |
| | | // |
| | | // /** |
| | | // * 解析JWT token |
| | | // * @param token JWT token |
| | | // * @return Claims对象 |
| | | // */ |
| | | // private Claims parseToken(String token) { |
| | | // try { |
| | | // return Jwts.parser() |
| | | // .setSigningKey(secret) |
| | | // .parseClaimsJws(token) |
| | | // .getBody(); |
| | | // } catch (Exception e) { |
| | | // log.error("解析token失败: {}", e.getMessage()); |
| | | // return null; |
| | | // } |
| | | // } |
| | | // |
| | | // /** |
| | | // * 获取token在Redis中的key |
| | | // * @param uuid 用户唯一标识 |
| | | // * @return Redis key |
| | | // */ |
| | | // private String getTokenKey(String uuid) { |
| | | // return com.ruoyi.common.constant.CacheConstants.LOGIN_TOKEN_KEY + uuid; |
| | | // } |
| | | // |
| | | // /** |
| | | // * 认证结果类 |
| | | // */ |
| | | // public static class AuthResult { |
| | | // private final boolean success; |
| | | // private final String message; |
| | | //// private final TAppUser appUser; |
| | | // |
| | | // private AuthResult(boolean success, String message) { |
| | | // this.success = success; |
| | | // this.message = message; |
| | | //// this.appUser = appUser; |
| | | // } |
| | | // |
| | | //// public static AuthResult success(TAppUser appUser) { |
| | | //// return new AuthResult(true, "认证成功", appUser); |
| | | //// } |
| | | //// |
| | | //// public static AuthResult failure(String message) { |
| | | //// return new AuthResult(false, message, null); |
| | | //// } |
| | | //// |
| | | //// public boolean isSuccess() { |
| | | //// return success; |
| | | //// } |
| | | //// |
| | | //// public String getMessage() { |
| | | //// return message; |
| | | //// } |
| | | //// |
| | | //// public TAppUser getAppUser() { |
| | | //// return appUser; |
| | | //// } |
| | | // } |
| | | // |
| | | // /** |
| | | // * 从认证消息中提取用户信息 |
| | | // * @param messageObj 消息对象 |
| | | // * @return 用户认证信息 |
| | | // */ |
| | | // public UserAuthInfo extractAuthInfo(Map<String, Object> messageObj) { |
| | | // String appUserId = (String) messageObj.get("appUserId"); |
| | | // String token = (String) messageObj.get("token"); |
| | | // String deviceId = (String) messageObj.get("deviceId"); |
| | | // String deviceType = (String) messageObj.get("deviceType"); |
| | | // |
| | | // return new UserAuthInfo(appUserId, token, deviceId, deviceType); |
| | | // } |
| | | // |
| | | // /** |
| | | // * 用户认证信息类 |
| | | // */ |
| | | // public static class UserAuthInfo { |
| | | // private final String appUserId; |
| | | // private final String token; |
| | | // private final String deviceId; |
| | | // private final String deviceType; |
| | | // |
| | | // public UserAuthInfo(String appUserId, String token, String deviceId, String deviceType) { |
| | | // this.appUserId = appUserId; |
| | | // this.token = token; |
| | | // this.deviceId = deviceId; |
| | | // this.deviceType = deviceType; |
| | | // } |
| | | // |
| | | // public String getAppUserId() { |
| | | // return appUserId; |
| | | // } |
| | | // |
| | | // public String getToken() { |
| | | // return token; |
| | | // } |
| | | // |
| | | // public String getDeviceId() { |
| | | // return deviceId; |
| | | // } |
| | | // |
| | | // public String getDeviceType() { |
| | | // return deviceType; |
| | | // } |
| | | // } |
| | | //} |