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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM