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;
|
|
|
|
/**
|
* 验证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;
|
}
|
|
|
|
/**
|
* 从认证消息中提取用户信息
|
* @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;
|
}
|
}
|
}
|