实战系列之《自定义注解实现登录拦截功能》

前言:实际项目里面,对于一些只有登陆之后的才能访问的接口,我是如何进行登录校验的!

本人在项目里,实现登录校验 是采用  拦截器+自定义注解的方式!

框架使用spring-boot 。版本 :2.3.4

逻辑流程:

1.用户在登陆成功之后,后台会生成一个token并返回给客户端,客户端需要保存token。在调用其他请求时,携带此token,到请求头中或者参数里。

2.后台通过拦截器,拦截到请求后,判断请求的方法或方法所属类 中是否存在  我们 标注的 登录校验注解,如果存在,表示当前请求需要校验用户是否登录,

3.去请求头里获取 token 数据,拿到token 去数据库校验(可以优化:存到缓存中,就不用每次去请求数据库了)、如果正确,则放行请求, 如果找不到token 或者校验 token已过期  ,则向外抛出异常。

逻辑图:

代码

自定义注解:用于标注在某个方法或类上,起到标识的作用!

/**
 * app登录效验 可作用方法 和类上 ,作用类上表示所有方法都会进行校验
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Login {
}

拦截器:拦截请求,判断请求目标方法是否标注了 @Login注解,无标注直接放行,有标注,则从请求头获取token 并校验合法性,校验通过放行,抛出异常!

/**
 * 权限(Token)验证拦截器
 *
 */
@Component
public class AuthorizationInterceptor extends HandlerInterceptorAdapter {

    public static final String USER_KEY = "userId";

    @Autowired
    private UserTokenService userTokenService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Login annotation;
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            //判断方法是否有标注注解
            annotation = handlerMethod.getMethodAnnotation(Login.class);
            if (annotation == null) {
                //判断方法所属类是否有标注注解
                annotation = handlerMethod.getMethod().getDeclaringClass().getAnnotation(Login.class);
                if (annotation == null) {
                    //放行
                    return true;
                }
            }
        } else {
            //放行
            return true;
        }

        //获取用户凭证
        String token = request.getHeader("token");
        if (StringUtils.isBlank(token)) {
            //请求头不存在就从参数中获取一次,增强兼容性
            token = request.getParameter("token");
        }

        //凭证为空
        if (StringUtils.isBlank(token)) {
            //向上抛出异常,需要全局异常处理器拦截该异常,并封装成统一的对象返回给前端
            throw new RRException("token不能为空", 401);
        }
        //根据accessToken,查询用户信息
        UserTokenService tokenEntity = userTokenService.queryByToken(token);
        //校验token的有效期是否过期
        if (tokenEntity == null || tokenEntity.getExpireTime().getTime() < System.currentTimeMillis()) {
            //向上抛出异常,需要全局异常处理器拦截该异常,并封装成统一的对象返回给前端
            throw new RRException("token失效,请重新登录", HttpStatus.UNAUTHORIZED.value());
        }
        //把用户id放到 request中 ,后续可以在方法中获取到
        request.setAttribute(USER_KEY, tokenEntity.getEtlUserId());
        return true;
    }
}

配置好拦截器后,我们需要 配置 拦截哪些地址,这里我们需要创建一个 WebMvcConfig,代码如下

/**
 * MVC配置
 */
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    //注入拦截器
    @Autowired
    private AuthorizationInterceptor authorizationInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //添加拦截器以及对应的拦截地址规则 ,/app/** 表示拦截路径中有 /app/下的所有请求
        registry.addInterceptor(authorizationInterceptor).addPathPatterns("/app/**");
    }

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {


    }
}

ok,以上就可以配置完毕了,剩下的就是使用了,在 /app/** 路径下的 接口上 打上 注解 @Login  注解 或者直接在类上打上@Login注解

/**
 * 用户相关

 */
@RestController
@RequestMapping("app/user")
public class AppUserController {


    /**
     * 获取登录用户信息
     */
    @Login//登录拦截注解
    @GetMapping("/test")
    public String test() throws IOException {
        return "ok";
    }

然后直接访问  http://localhost:8080/app/user/test ,不出意外 会直接返回 异常信息了,这里需要写一个全局异常处理器 拦截 RRException 自定义的异常信息和code码,然后组拼成 一个通用的返回值对象就可以了!
如果你在项目中使用了其他方案实现了 登录校验,请留言讨论,我们互相学习

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值