修复WebSocket身份认证问题
- 添加WebSocketAuthInterceptor处理token认证 - 修改WebSocket连接逻辑,支持token传递 - 统一用户身份识别,确保登录用户使用USER类型 - 修复前端环境变量配置,统一WebSocket URL - 添加Token测试页面用于验证功能 - 更新聊天消息处理逻辑,正确识别用户身份 解决了登录用户发送消息时同时保存GUEST和USER两种类型数据的问题
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
package com.emotion.interceptor;
|
||||
|
||||
import com.emotion.service.AuthService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.messaging.simp.stomp.StompCommand;
|
||||
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
|
||||
import org.springframework.messaging.support.ChannelInterceptor;
|
||||
import org.springframework.messaging.support.MessageHeaderAccessor;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* WebSocket认证拦截器
|
||||
* 用于在WebSocket连接时验证用户身份
|
||||
*
|
||||
* @author emotion-museum
|
||||
* @date 2025-07-24
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class WebSocketAuthInterceptor implements ChannelInterceptor {
|
||||
|
||||
@Autowired
|
||||
private AuthService authService;
|
||||
|
||||
@Override
|
||||
public Message<?> preSend(Message<?> message, MessageChannel channel) {
|
||||
StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);
|
||||
|
||||
if (accessor != null && StompCommand.CONNECT.equals(accessor.getCommand())) {
|
||||
// 处理WebSocket连接时的认证
|
||||
handleAuthentication(accessor);
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理WebSocket连接认证
|
||||
*/
|
||||
private void handleAuthentication(StompHeaderAccessor accessor) {
|
||||
try {
|
||||
// 从连接头中获取token
|
||||
String authHeader = accessor.getFirstNativeHeader("Authorization");
|
||||
String userId = accessor.getFirstNativeHeader("X-User-Id");
|
||||
|
||||
log.info("WebSocket连接认证: authHeader={}, userId={}",
|
||||
authHeader != null ? "Bearer ***" : null, userId);
|
||||
|
||||
if (StringUtils.hasText(authHeader) && authHeader.startsWith("Bearer ")) {
|
||||
String token = authHeader.substring(7);
|
||||
|
||||
// 验证token
|
||||
if (authService.validateToken(token)) {
|
||||
String tokenUserId = authService.getUserIdFromToken(token);
|
||||
String username = authService.getUsernameFromToken(token);
|
||||
|
||||
log.info("WebSocket token验证成功: userId={}, username={}", tokenUserId, username);
|
||||
|
||||
// 创建认证对象
|
||||
Authentication authentication = new UsernamePasswordAuthenticationToken(
|
||||
tokenUserId,
|
||||
null,
|
||||
Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER"))
|
||||
);
|
||||
|
||||
// 设置用户认证信息
|
||||
accessor.setUser(authentication);
|
||||
|
||||
// 设置会话属性
|
||||
accessor.getSessionAttributes().put("userId", tokenUserId);
|
||||
accessor.getSessionAttributes().put("username", username);
|
||||
accessor.getSessionAttributes().put("authenticated", true);
|
||||
|
||||
} else {
|
||||
log.warn("WebSocket token验证失败: token无效");
|
||||
// token无效,但不阻止连接,作为访客处理
|
||||
handleGuestUser(accessor, userId);
|
||||
}
|
||||
} else {
|
||||
log.info("WebSocket连接无token,作为访客处理: userId={}", userId);
|
||||
// 无token,作为访客处理
|
||||
handleGuestUser(accessor, userId);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("WebSocket认证处理失败", e);
|
||||
// 认证失败,作为访客处理
|
||||
handleGuestUser(accessor, accessor.getFirstNativeHeader("X-User-Id"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理访客用户
|
||||
*/
|
||||
private void handleGuestUser(StompHeaderAccessor accessor, String userId) {
|
||||
String guestId = StringUtils.hasText(userId) ? userId : "guest_" + System.currentTimeMillis();
|
||||
|
||||
log.info("设置访客用户: guestId={}", guestId);
|
||||
|
||||
// 创建访客认证对象
|
||||
Authentication guestAuth = new UsernamePasswordAuthenticationToken(
|
||||
guestId,
|
||||
null,
|
||||
Collections.singletonList(new SimpleGrantedAuthority("ROLE_GUEST"))
|
||||
);
|
||||
|
||||
accessor.setUser(guestAuth);
|
||||
|
||||
// 设置会话属性
|
||||
accessor.getSessionAttributes().put("userId", guestId);
|
||||
accessor.getSessionAttributes().put("username", guestId);
|
||||
accessor.getSessionAttributes().put("authenticated", false);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user