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.......

原文地址:https://www.cnblogs.com/gjmhome/p/14514351.html