文章目录
- 1、debug发现问题
- 2、发现 userId 为空
- 3、GuiGuAspect
- 4、@GuiGuLogin
1、debug发现问题
2、发现 userId 为空
点击 getUserId() 进入方法内部
package com.atguigu.tingshu.common.util;
/**
* 获取当前用户信息帮助类
*/
public class AuthContextHolder {
private static ThreadLocal<Long> userId = new ThreadLocal<Long>();
private static ThreadLocal<String> username = new ThreadLocal<String>();
public static void setUserId(Long _userId) {
userId.set(_userId);
}
public static Long getUserId() {
return userId.get();
}
public static void removeUserId() {
userId.remove();
}
public static void setUsername(String _username) {
username.set(_username);
}
public static String getUsername() {
return username.get();
}
public static void removeUsername() {
username.remove();
}
}
3、GuiGuAspect
package com.atguigu.tingshu.common.login;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
@Aspect
@Component
public class GuiGuAspect {
@Autowired
private RedisTemplate redisTemplate;
/**
* 环绕通知,用于处理登录鉴权
* 该方法在目标方法执行前后都会执行,用于校验用户是否已经登录
* 如果用户已经登录,则设置用户ID和用户名到上下文中
* 如果用户未登录且注解标记为必需登录,则抛出异常
*
* @param joinPoint 切入点对象,用于获取目标方法和其参数
* @param guiGuLogin 注解对象,用于判断是否必需登录
* @return 目标方法的执行结果
* @throws Throwable 目标方法可能抛出的异常
*/
@Around("@annotation(guiGuLogin)")
public Object auth(ProceedingJoinPoint joinPoint, GuiGuLogin guiGuLogin) throws Throwable {
// 获取HttpServletRequest对象
ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
// 获取token,用于后续的用户身份验证
String token = request.getHeader("token");
// 判断token是否为空,如果不为空,则尝试从redis中获取用户信息
UserInfoVo userInfoVo = null;
if (StringUtils.isNotBlank(token)){
// 查询redis中获取用户的登录信息
userInfoVo = (UserInfoVo)this.redisTemplate.opsForValue().get(RedisConstant.USER_LOGIN_KEY_PREFIX + token);
// 如果获取到用户信息,则将用户ID和用户名设置到上下文中
if (userInfoVo != null){
AuthContextHolder.setUserId(userInfoVo.getId());
AuthContextHolder.setUsername(userInfoVo.getNickname());
}
}
// 如果没有登录并且是必须登录的情况下,应该抛出异常提示未登录
if (guiGuLogin.required() && userInfoVo == null){
throw new GuiguException(ResultCodeEnum.LOGIN_AUTH);
}
// 执行目标方法
Object result = joinPoint.proceed(joinPoint.getArgs());
// 清除上下文中的用户信息,释放ThreadLocal,防止内存泄漏
AuthContextHolder.removeUserId();
AuthContextHolder.removeUsername();
// 返回目标方法的执行结果
return result;
}
}
我们是在切面类 GuiGuAspect 里面获取的 userId ,所以我们需要在指定的方法上面加上 切面注解@GuiGuLogin
4、@GuiGuLogin
package com.atguigu.tingshu.common.login;
import java.lang.annotation.*;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface GuiGuLogin {
boolean required() default true;
}
这样问题就可以得到解决。