Abstract: This paper introduces four ways to implement universal AuTH in Spring-Boot, including traditional AOP, interceptor, parameter parser and filter, and provides the corresponding example code, and finally summarizes the order of their execution.

Share this article from huawei cloud community farmers “code architecture | Spring Boot 4 ways to realize general Auth authentication”, the author: code agricultural structure.

One, foreword

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.

Two, 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:

  • Declare the WhitelistAspect class using @aspect;

  • Add a pointcut whitelistPointcut() to the cut class. To implement the ability of this pointcut to be flexible and assemblable, instead of using an execution full intercept, add an annotation @whitelist so that the annotated method validates the Whitelist.

  • Use Spring’s AOP annotation @before in the aspect class to declare a notification method checkWhitelist() that validates 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.

▐ expand

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.

Third, 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 AppkeyInterceptor class and implement HandlerInterceptor interface.

2. Implement its preHandle() method;

3. Check whether to intercept a request using annotations and parameters in the preHandle method. The interface returns false when the request is intercepted.

4. Register the interceptor in the custom WebMvcConfigurerAdapter class.

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

▐ expand

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.

Four, 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 the user-defined parameter type AuthParam, which contains the appKey related field;

2. Define AuthParamResolver and realize the interface HandlerMethodArgumentResolver;

3. Implement supportsParameter() interface method to match AuthParam with AuthParamResolver;

4. Implement resolveArgument() interface method to parse reqest object to generate AuthParam object, and verify AuthParam to confirm whether AppKey is in the whitelist;

5. Add the AuthParam parameter to the Controller Action signature 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(); } } jCopy the code

▐ expand

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.

Five, the 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

▐ expand

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

Six, summarized

Each of the four implementations has its own appropriate scenarios, 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.

Click to follow, the first time to learn about Huawei cloud fresh technology ~