• SpringBoot自定义注解示例分析——实现Token校验


    当看到这个标题时,突然想到之前找工作时,室友被面试官问有没有自定义过注解,室友蒙了,回来告诉我们,结果我们一圈蒙了......

    今天看到这个题目,不得不来补一下之前的旧账了,万一以后面试再被cue呢?

    好了,话不多说。


    今天我们实现的自定义注解是一个Token验证。

    一共分如下几步:

    1.定义Token的注解,需要Token校验的接口,方法上加上此注解;

    1 import java.lang.annotation.ElementType;
    2 import java.lang.annotation.Retention;
    3 import java.lang.annotation.RetentionPolicy;
    4 import java.lang.annotation.Target;
    5 @Retention(RetentionPolicy.RUNTIME)
    6 @Target(ElementType.METHOD)
    7 public @interface Token {
    8     boolean validate() default true;
    9 }

    2.定义LoginUser注解,此注解加在参数上,用在需要从token里获取的用户信息的地方;

    1 import java.lang.annotation.ElementType;
    2 import java.lang.annotation.Retention;
    3 import java.lang.annotation.RetentionPolicy;
    4 import java.lang.annotation.Target;
    5 @Target(ElementType.PARAMETER)
    6 @Retention(RetentionPolicy.RUNTIME)
    7 public @interface LoginUser {
    8 }

    3.权限的校验拦截器;

     1 import com.example.demo.annotation.Token;
     2 import com.example.demo.entity.User;
     3 import lombok.extern.slf4j.Slf4j;
     4 import org.springframework.stereotype.Component;
     5 import org.springframework.web.method.HandlerMethod;
     6 import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
     7 import javax.servlet.http.HttpServletRequest;
     8 import javax.servlet.http.HttpServletResponse;
     9 @Component
    10 @Slf4j
    11 public class AuthorizationInterceptor extends HandlerInterceptorAdapter {
    12     public static final String USER_KEY = "USER_ID";
    13     public static final String USER_INFO = "USER_INFO";
    14     @Override
    15     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    16         Token annotation;
    17         if(handler instanceof HandlerMethod) {
    18             annotation = ((HandlerMethod) handler).getMethodAnnotation(Token.class);
    19         }else{
    20             return true;
    21         }
    22         //没有声明需要权限,或者声明不验证权限
    23         if(annotation == null || annotation.validate() == false){
    24             return true;
    25         }
    26         //从header中获取token
    27         String token = request.getHeader("token");
    28         if(token == null){
    29             log.info("缺少token,拒绝访问");
    30             return false;
    31         }
    32         //查询token信息
    33 //        User user = redisUtils.get(USER_INFO+token,User.class);
    34 //        if(user == null){
    35 //            log.info("token不正确,拒绝访问");
    36 //            return false;
    37 //        }
    38         //token校验通过,将用户信息放在request中,供需要用user信息的接口里从token取数据
    39         request.setAttribute(USER_KEY, "123456");
    40         User user=new User();
    41         user.setId(10000L);
    42         user.setUserName("2118724165@qq.com");
    43         user.setPhoneNumber("15702911111");
    44         user.setToken(token);
    45         request.setAttribute(USER_INFO, user);
    46         return true;
    47     }
    48 }

    4.写参数的解析器,将登陆用户对象注入到接口里;

     1 import com.example.demo.annotation.LoginUser;
     2 import com.example.demo.entity.User;
     3 import com.example.demo.interceptor.AuthorizationInterceptor;
     4 import org.springframework.core.MethodParameter;
     5 import org.springframework.stereotype.Component;
     6 import org.springframework.web.bind.support.WebDataBinderFactory;
     7 import org.springframework.web.context.request.NativeWebRequest;
     8 import org.springframework.web.context.request.RequestAttributes;
     9 import org.springframework.web.method.support.HandlerMethodArgumentResolver;
    10 import org.springframework.web.method.support.ModelAndViewContainer;
    11 @Component
    12 public class LoginUserHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver
    13 {
    14     @Override
    15     public boolean supportsParameter(MethodParameter methodParameter) {
    16         return methodParameter.getParameterType().isAssignableFrom(User.class)&&methodParameter.hasParameterAnnotation(LoginUser.class);
    17     }
    18     @Override
    19     public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
    20         //获取登陆用户信息
    21         Object object = nativeWebRequest.getAttribute(AuthorizationInterceptor.USER_INFO, RequestAttributes.SCOPE_REQUEST);
    22         if(object == null){
    23             return null;
    24         }
    25         return (User)object;
    26     }
    27 }

    5.配置拦截器和参数解析器;

     1 import com.example.demo.interceptor.AuthorizationInterceptor;
     2 import com.example.demo.resolver.LoginUserHandlerMethodArgumentResolver;
     3 import org.springframework.beans.factory.annotation.Autowired;
     4 import org.springframework.context.annotation.Configuration;
     5 import org.springframework.web.method.support.HandlerMethodArgumentResolver;
     6 import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
     7 import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
     8 import java.util.List;
     9  
    10 @Configuration
    11 public class WebMvcConfig implements WebMvcConfigurer {
    12     @Autowired
    13     private AuthorizationInterceptor authorizationInterceptor;
    14     @Autowired
    15     private LoginUserHandlerMethodArgumentResolver loginUserHandlerMethodArgumentResolver;
    16  
    17     @Override
    18     public void addInterceptors(InterceptorRegistry registry) {
    19         registry.addInterceptor(authorizationInterceptor).addPathPatterns("/api/**");
    20     }
    21  
    22     @Override
    23     public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
    24         argumentResolvers.add(loginUserHandlerMethodArgumentResolver);
    25     }
    26 }

    6.测试类;

     1 import com.example.demo.annotation.LoginUser;
     2 import com.example.demo.annotation.Token;
     3 import com.example.demo.entity.User;
     4 import lombok.extern.slf4j.Slf4j;
     5 import org.springframework.web.bind.annotation.RequestMapping;
     6 import org.springframework.web.bind.annotation.RequestMethod;
     7 import org.springframework.web.bind.annotation.RestController;
     8  
     9 @RestController
    10 @RequestMapping(value = "/api")
    11 @Slf4j
    12 public class TestController {
    13     @RequestMapping(value="/test",method = RequestMethod.POST)
    14     @Token
    15     public String test(@LoginUser User user){
    16         System.out.println("需要token才可以访问,呵呵……");
    17         log.info("user:"+user.toString());
    18         return "test";
    19     }
    20     @RequestMapping(value="/noToken",method = RequestMethod.POST)
    21     public String noToken(){
    22         System.out.println("不用token就可以访问……");
    23         return "test";
    24     }
    25 }

    至此,自定义注解实现token校验就大功告成了。

    参考及致谢:

    1、SpringBoot自定义注解实现

    2、Spring Boot项目中自定义注解的使用

    Over.......

  • 相关阅读:
    jar
    8月21日23:38
    WPF之UI虚拟化
    (转)Windows系统白名单以及UAC机制
    C#获取文件版本信息
    命名实体识别,使用pyltp提取文本中的地址
    (转载)完成端口(Completion Port, I/OCP)详解
    全国各城市地名抓取,包含街道、村落、小区、商店、景点等
    关于Python打包运行的一些思路
    关于批判性思维(Critical Thinking)
  • 原文地址:https://www.cnblogs.com/gjmhome/p/14514351.html
Copyright © 2020-2023  润新知