注解+AOP实现全局登录认证效验(附代码)

1. 需求分析

在登录后,前端每次向后端发起请求都需要携带下发的token,而后端的每个方法都需要效验token是否有效。当然可以提取出公共的方法,但是终归是与我们业务逻辑无关的代码,而且修改需要改动原来的业务代码,造成耦合
而通过注解+AOP就能很好的解耦合,提高扩展性

2. 什么是AOP

说到AOP第一个想到的肯定是面向切面编程。在传统的面向对象编程(OOP)中,横切关注点如日志、事务管理、安全性等通常会散布在多个模块中,这会导致代码的重复和混乱。AOP的目的是通过将这样的关注点从业务逻辑中分离出来,使得它们可以在一个集中的地方被管理和维护。主要分为如下三部分

  1. 切入点 - 实际增强的方法
  2. 增强 - 需要实现的增强逻辑代码
  3. 切面 - 是一个操作,指把增强使用到切入点的过程

3. 实现

在项目的公共模块common-util中创建如下,也可以根据自己项目架构选择

3.1 新建注解 @DaiJiaLogin

//方法前校验是否登录
@Target(ElementType.METHOD) //在方法上生效
@Retention(RetentionPolicy.RUNTIME) //运行时
public @interface DaiJiaLogin {
}

3.2 新建切面类

@Component
@Aspect //切面类
public class DaiJiaAspect {
    
}

3.3 在切面类中定义增强方法

注意增强方法上标注的是环绕,格式固定,根据自己的项目架构来修改

“execution(* com.charles.daijia..controller..*(…)) *代表任意的权限修饰符 在com.charles.daijia包名下的controller下的任意类里面任意方法,方法能有任意参数(…)
&&
@annotation(daiJiaLogin)” 同时必需要有这个注解才增强方法

@Resource
private RedisTemplate redisTemplate;

@Around("execution(* com.charles.daijia.*.controller.*.*(..)) && @annotation(daiJiaLogin)")
public void process(ProceedingJoinPoint proceedingJoinPoint, DaiJiaLogin daiJiaLogin) throws Throwable {
    //获取请求
    RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
    ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
    HttpServletRequest request = servletRequestAttributes.getRequest();

    //请求中得到请求头的token
    String token = request.getHeader("token");

    if(token == null)
        throw new DaiJiaException(ResultCodeEnum.LOGIN_AUTH);

    //在redis中查找是否存在token
    String id = (String) redisTemplate.opsForValue().get(RedisConstant.USER_LOGIN_KEY_PREFIX + token);

    if(id == null)
        throw new DaiJiaException(ResultCodeEnum.LOGIN_AUTH);

    //放入localstorage中
    AuthContextHolder.setUserId(Long.parseLong(id));

    proceedingJoinPoint.proceed();
}

3.4 使用

只需要在响应的方法上标注@DaiJiaLogin 这个注解就能实现我们需求的功能,而不需改动原有的业务代码

//获取登录用户信息
@Operation(summary = "登录后拉取用户信息")
@DaiJiaLogin  // 切面增强实现效验登录是否过期
@GetMapping("/getCustomerLoginInfo")
public Result<CustomerLoginVo> getCustomerLoginInfo(){
    //直接从threadLocal中获取
    Long userId = AuthContextHolder.getUserId();

    return Result.ok(customerService.getCustomerLoginInfo(userId));
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值