登录注解aop

登录注解aop

资料参考地址1: spring-AOP 及 AOP获取request各项参数操作

需求: 通过请求头中的token查询用户信息,存放到ThreadLocal中

注意:有许多接口对外开放,不可用统一拦截器来验证是否登录

登录注解

/**
 * 登录注解
 * @author lyn
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequiredLogin {
    /**
     * 是否必须登录,默认true,false为测试用,如果值为false且使用了UserHandler,会抛出空指针异常
     * @return
     */
    boolean isRequiredLogin() default true;
}

登录aop

import cn.hutool.core.util.StrUtil;
import com.aliyuncs.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterReturning;
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.cuour.account.common.constant.SystemConstants;
import org.cuour.account.common.dto.SysUserDto;
import org.cuour.account.common.dto.UserDetailDto;
import org.cuour.account.rpc.api.CheckAuthTokenService;
import org.cuour.account.rpc.api.SalesServiceRpc;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.Order;
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;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Objects;

/**
 * 登录aop
 *
 * @author lyn
 * @date 2022/6/6 11:03
 */
@Aspect
@Component
@Slf4j
@Order(5)
public class RequiredLoginAspect {

    private final static String USER_ID = "USER-ID";

    /**
     * 令牌自定义标识
     */
    @Value("${token.header}")
    private String header;

    /**
     * 定义切点 切点为
     */
    @Pointcut("@annotation(org.hjxr.cc.rest.annotation.RequiredLogin)")
    public void pointcutLogin() {
    }

    @Before("pointcutLogin()")
    public void verifyLogin(JoinPoint joinPoint) {
        RequiredLogin requiredLogin = getAnnotationRequiredLogin(joinPoint);
        boolean isRequiredLogin = requiredLogin.isRequiredLogin();
        if (isRequiredLogin) {
            // 获取原始的HttpServletRequest
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
            String token = request.getHeader(this.header);
            String userId = request.getHeader(USER_ID);
            UserDetailDto userDetailDto = null;
            //通过请求头中的token或者userId获取当前用户信息,省略
            if (Objects.isNull(userDetailDto)) {
                throw new BizException(2001000000, "认证信息有误");
            }
            UserHandler.setUserInfo(userDetailDto);
        }
    }

    /**
     * 获取注解
     *
     * @param joinPoint
     * @return
     */
    private RequiredLogin getAnnotationRequiredLogin(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();

        if (method != null) {
            return method.getAnnotation(RequiredLogin.class);
        }
        throw new BizException(BizMessage.SYSTEM_EXCEPTION);
    }

    @AfterReturning(pointcut = "pointcutLogin()")
    public void doAfterReturning(JoinPoint joinPoint) {
        RequiredLogin requiredLogin = getAnnotationRequiredLogin(joinPoint);
        boolean isRequiredLogin = requiredLogin.isRequiredLogin();
        UserHandler.removeUserInfo();
        if (isRequiredLogin) {
            // 删除ThreadLocal中的数据,以防内存泄露问题
            UserHandler.removeUserInfo();
        }
    }
}

ThreadLocal

/**
 * threadLocal工具类操作user对象
 * @author lyn
 */
public class UserHandler {

    private static final ThreadLocal<UserDetailDto> TL = new ThreadLocal<>();

    /**
     * 向线程内存储user
     * @param user
     */
    public static void setUserInfo(UserDetailDto user) {
        TL.set(user);
    }

    /**
     * 从线程内获取user
     * @return
     */
    public static UserDetailDto getUserInfo() {
        return TL.get();
    }

    /**
     * 删除线程内user
     */
    public static void removeUserInfo() {
        TL.remove();
    }

}

 

posted @ 2022-06-06 14:52  进击的小蔡鸟  阅读(67)  评论(0编辑  收藏  举报