package com.poyee.aspect; import cn.hutool.core.util.StrUtil;import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.poyee.annotation.NoLogin; import com.poyee.annotation.UserLoginToken; import com.poyee.exception.BusinessException; import com.poyee.utils.JwtUtils; import com.poyee.utils.ServletUtils; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.Signature; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; import java.lang.reflect.Method; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Base64; /** * 用户登录Token切面 */ @Slf4j @Aspect @Component public class UserLoginTokenAspect { /** * 配置织入点 - 拦截所有 Controller 方法 */ @Pointcut("execution(public * com.poyee.controller.*.*(..))") public void controllerPointCut() { } /** * 前置通知 */ @Before("controllerPointCut()") public void doBefore(JoinPoint joinPoint) { HttpServletRequest request = ServletUtils.getRequest(); if (request == null) { return; } // 获取方法上的注解 Signature signature = joinPoint.getSignature(); MethodSignature methodSignature = (MethodSignature) signature; Method method = methodSignature.getMethod(); Class declaringClass = method.getDeclaringClass(); // 1. 检查是否有 @NoLogin 注解(方法级别优先) NoLogin noLogin = method.getAnnotation(NoLogin.class); if (noLogin == null) { noLogin = declaringClass.getAnnotation(NoLogin.class); } // 如果有 @NoLogin 注解,直接放行 if (noLogin != null) { return; } // 2. 没有 @NoLogin 注解,一律进行 Token 检查 String userInfoStr = request.getHeader("X-USER-BASE64"); if (StrUtil.isBlank(userInfoStr)) { userInfoStr = request.getHeader("x-user-base64"); } log.info("X-USER-BASE64 >>> {}", userInfoStr); String authorization = request.getHeader("Authorization"); log.info("Authorization >>> {}", authorization); // 3. 检查是否有 @UserLoginToken 注解(用于角色控制) UserLoginToken userLoginToken = method.getAnnotation(UserLoginToken.class); if (userLoginToken == null) { userLoginToken = declaringClass.getAnnotation(UserLoginToken.class); } // 执行登录检查 checkUserLoginToken(request, userInfoStr, authorization, userLoginToken); } /** * 检查用户登录Token */ private void checkUserLoginToken(HttpServletRequest request, String userInfoStr, String authorization, UserLoginToken userLoginToken) { boolean isAuthorization = false; String token = userInfoStr; // 1. 尝试从 X-USER-BASE64 获取 if (StrUtil.isBlank(token)) { // 2. 尝试从 Authorization 获取 if (StrUtil.isNotBlank(authorization)) { if (authorization.startsWith("Bearer ")) { isAuthorization = true; token = authorization.substring(7); } else { token = authorization; } } } if (StrUtil.isBlank(token)) { throw new BusinessException(401, "未登录或登录已过期"); } // 保存原始token到session ServletUtils.getSession().setAttribute("x-user-base64", token); // 解析用户信息 JSONObject userInfo = parseUserInfo(token, isAuthorization); if (userInfo == null) { throw new BusinessException(402, "登录信息无效,请重新登录"); } // 保存用户信息到request request.setAttribute("currentUser", userInfo); ServletUtils.getSession().setAttribute("userInfo", JSON.toJSONString(userInfo)); // 检查角色权限(如果有 @UserLoginToken 注解且配置了角色) if (userLoginToken != null && userLoginToken.roles().length > 0) { boolean hasRole = checkRole(userInfo, userLoginToken.roles()); if (!hasRole) { throw new BusinessException(403, "无权访问"); } } log.info("用户登录验证通过: {}", userInfo.getString("username")); } /** * 解析用户信息 */ private JSONObject parseUserInfo(String token, boolean isAuthorization) { try { if (isAuthorization) { // JWT Token 解析 return JwtUtils.getTokenUserInfo(token); } else { // Base64 编码的用户信息 String jsonStr = new String(Base64.getDecoder().decode(token), StandardCharsets.UTF_8); return JSON.parseObject(jsonStr); } } catch (Exception e) { log.error("解析用户信息失败", e); return null; } } /** * 检查用户角色 */ private boolean checkRole(JSONObject userInfo, String[] requiredRoles) { if (userInfo == null) { return false; } String role = userInfo.getString("role"); if (role == null) { return false; } return Arrays.asList(requiredRoles).contains(role); } }