From: Pillow book

Link: zhenbianshu. Making. IO /

This article introduces four ways to implement universal AuTH in Spring-Boot, including traditional AOP, interceptor, parameter parser and filter, and provides the corresponding example code. Finally, it briefly summarizes their execution order.

preface

Has recently been submerged by the endless business requirements, and don’t have time to breathe, finally received a comfort zone of work makes me break code, solve its process is very tortuous, once let I doubt the life, but the harvest is very big also, code is not obvious, but felt erased Java, Tomcat, Spring has been blocked in front of my eyes a layer of yarn. A new level of understanding. I haven’t output for a long time, so I choose one aspect to summarize, hoping to learn some other things in the process of combing.

Due to Java’s thriving ecosystem, each of the following modules has a large number of articles devoted to it. So I chose another Angle, starting from a practical problem, to connect these scattered pieces of knowledge, you can look at it as a summary. For the ultimate details of each module, check out the official documentation or other blogs on the web. The requirement was simple and clear, not at all the sexy requirement that the product mentioned: add a common appKey whitelist verification function to our Web framework and hope that it would be more scalable.

This Web framework is implemented by the predecessor of the department based on Spring-boot. It is between the service and the Spring framework and performs some general functions biased to the service, such as log output, function switch, and general parameter analysis. Normally transparent to the business, recently so busy getting the requirements right and the code right that it never even noticed it existed.

Traditional AOP

The first thing that comes to mind for this requirement is, of course, the AOP interface provided by Spring-Boot; you just need to add pointcuts in front of the Controller method and then work with them.

implementation

The steps are as follows:

  1. use@AspectDeclare the section classWhitelistAspect;
  2. Adds a pointcut to the section classwhitelistPointcut()In order to achieve the ability of this pointcut to be flexible and assemblable, it is not used hereexecutionIntercept them all, but add an annotation@WhitelistAnnotated methods are whitelisted.
  3. Use Spring’s AOP annotations in the faceted classes@BeforeDeclare a notification methodcheckWhitelist()Verify the whitelist before the Controller method is executed.

The pseudocode of the section class is as follows:

@Aspect public class WhitelistAspect { @Before(value = "whitelistPointcut() && @annotation(whitelist)") public void checkAppkeyWhitelist(JoinPoint joinPoint, Whitelist whitelist) { checkWhitelist(); Joinpoint.getargs () = joinPoint.getargs (); @Pointcut("@annotation(com.zhenbianshu.Whitelist)") public void whitelistPointCut() { } }Copy the code

Add the @whitelist annotation to the Controller method.

extension

In this example, annotations are used to declare pointcuts, and I have implemented the annotation parameter to declare whitelists to be verified. If you need to add other whitelists later, such as by UID, you can add methods such as UID () to this annotation to implement custom validation. In addition, Spring’s AOP supports pointcut declaration methods such as execution, bean (the execution method of a bean object that matches a particular name), and notification methods such as @around (executed within the execution of the target function) and @After (After the execution of the method). So, the functionality has been implemented, but the leader is not satisfied with =_=, because there is too much AOP in the project, it is overused, and suggested that I take a different approach. Well, we have to.

Interceptor

Spring’s Interceptor is also a great way to do this. As the name suggests, interceptors are used to determine whether or not an Action should be executed in a Controller with some parameters before it is executed. To implement an interceptor, you can implement Spring’s HandlerInterceptor interface.

implementation

The implementation steps are as follows:

  1. Define the interceptor classAppkeyInterceptorClass and implement the HandlerInterceptor interface.
  2. To achieve itspreHandle()Methods;
  3. The preHandle method uses annotations and parameters to determine whether a request needs to be interceptedfalse;
  4. In customWebMvcConfigurerAdapterClass to register the interceptor;

The AppkeyInterceptor class is as follows:

@Component public class WhitelistInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { Whitelist whitelist = ((HandlerMethod) handler).getMethodAnnotation(Whitelist.class);  // whitelist.values(); Return true; return true; return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView ModelAndView) throws Exception {// Method executes after Controller method execution} @override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Throws Exception {// Execute after view rendering is complete}}Copy the code

extension

To enable the interceptor, you also need to explicitly configure it to be enabled, which is configured using the WebMvcConfigurerAdapter. Note that the MvcConfiguration that inherits it needs to be in the ComponentScan path.

@Configuration public class MvcConfiguration extends WebMvcConfigurerAdapter { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new WhitelistInterceptor()).addPathPatterns("/*").order(1); If multiple interceptors exist, any interceptor returning false will cause subsequent request methods to stop executing}}Copy the code

Note also that the response code is 200 after successful execution of the interceptor, but the response data is empty. Spring Boot basic tutorial and sample source code here to learn: github.com/javastacks/… We already have an Auth parameter, appKey can be retrieved from the Auth parameter, we can whitelist Auth as a way, why not check Auth? Emmm… Vomiting blood.

ArgumentResolver

The parameter parser is a spring-provided tool for parsing custom parameters. The @RequestParam annotation is a shadow of this and allows you to combine the parameters into the desired shape before entering the Controller Action. Spring maintains a ResolverList. When a request arrives, Spring finds parameters of a custom type (non-basic type) and tries these in turn until one Resolver resolves the required parameters. To implement a parser parameters, need to implement the interface HandlerMethodArgumentResolver.

implementation

  1. Define a custom parameter typeAuthParam, class has appKey related fields;
  2. defineAuthParamResolverAnd implement HandlerMethodArgumentResolver interface;
  3. implementationsupportsParameter()The interface method ADAPTS AuthParam to AuthParamResolver.
  4. implementationresolveArgument()The interface method parses the Reqest object to generate an AuthParam object and validates the AuthParam object to verify whether appKey is in the whitelist.
  5. Add the AuthParam parameter to the signature on the Controller Action method to enable this Resolver;

The AuthParamResolver class is implemented as follows:

@Component public class AuthParamResolver implements HandlerMethodArgumentResolver { @Override public boolean supportsParameter(MethodParameter parameter) { return parameter.getParameterType().equals(AuthParam.class); } @Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { Whitelist whitelist = parameter.getMethodAnnotation(Whitelist.class); Return new AuthParam(); }}Copy the code

extension

Of course, using the parameter parser also requires a separate configuration, which we also configure in the WebMvcConfigurerAdapter:

@Configuration public class MvcConfiguration extends WebMvcConfigurerAdapter { @Override public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) { argumentResolvers.add(new AuthParamResolver()); }}Copy the code

After the implementation this time, I was still a little worried, so I searched on the Internet to see if there are other ways to realize this function, and FOUND that Filter is also common.

Filter

Filters are not provided by Spring; they are defined in the Servlet specification and are supported by the Servlet container. Requests that are filtered by Filter are not dispatched to the Spring container. Its implementation is also relatively simple, javax.servlet.filter interface can be implemented. Since the Filter is not in the Spring container, it does not get the resources of the Spring container, so you have to use the native Java ServletRequest and ServletResponse to get the request parameters. In addition, the doFilter method calling FilterChain must be displayed in a Filter, otherwise the request is considered to be blocked. The implementation is similar to:

public class WhitelistFilter implements javax.servlet.Filter { @Override public void init(FilterConfig filterConfig) Throws ServletException {// Called once after initialization} @override public void doFilter(ServletRequest Request, ServletResponse Response, FilterChain chain) throws IOException, ServletException {// Check whether chain.doFilter(request, response); } @override public void destroy() {// Call once when destroyed}}Copy the code

extension

Filter also needs to display the configuration:

@Configuration public class FilterConfiguration { @Bean public FilterRegistrationBean someFilterRegistration() { FilterRegistrationBean registration = new FilterRegistrationBean(); registration.setFilter(new WhitelistFilter()); registration.addUrlPatterns("/*"); registration.setName("whitelistFilter"); registration.setOrder(1); // Set the order in which filters are called. }}Copy the code

summary

Each of the four implementations has its own appropriate landscape, so what is the order of calls between them? The Filter is implemented by Servlet, so it is called first, followed by the Interceptor, which does not need further processing, followed by the parameter parser, and finally the cutting point of the section.

Recommend 2 original Springboot +Vue projects, with complete video explanation and documentation and source code:

【VueAdmin】 hand to hand teach you to develop SpringBoot+Jwt+Vue back-end separation management system

  • Video tutorial: www.bilibili.com/video/BV1af…
  • Complete development document front end: www.zhuawaba.com/post/18
  • Full development documentation backend: www.zhuawaba.com/post/19

【VueBlog】 Based on SpringBoot+Vue development of the front and back end separation blog project complete teaching

  • Video tutorial: www.bilibili.com/video/BV1af…
  • Full development documentation: www.zhuawaba.com/post/17

If you have any questions, please come to my official account [Java Q&A Society] and ask me