This article is shared from Huawei cloud community< Code farming architecture | four ways of realizing general Auth authentication with Spring Boot >, author: Code farmer architecture.
1, Foreword
Due to the prosperous ecology of Java, a large number of articles are devoted to each module below. So I chose another perspective, starting from practical problems, to connect these scattered knowledge. You can take it as a summary. For the ultimate detailed introduction of each module, you can turn to the official documents or see other blogs on the network.
The requirements are very simple and clear, which is not the same as the flirtatious requirements proposed by the products: a general appkey whitelist verification function is added to our web framework. I hope it has better scalability.
This web framework is implemented by the Department pioneer based on Spring boot. It is between the business and the Spring framework. It does some business oriented general functions, such as log output, function switch, general parameter parsing, etc. It is usually transparent to the business. Recently, it has been busy doing a good job in requirements and writing code, and has never even noticed its existence.
2, Traditional AOP
For this requirement, the first thought is of course the AOP interface provided by spring boot. You only need to add the pointcut in front of the Controller method, and then process the pointcut.
♪ implementation
Its use steps are as follows:
- Use @ Aspect to declare the Aspect class WhitelistAspect;
- Add a pointcut whitelistPointcut() in the facet class. In order to realize the ability of flexible assembly of this pointcut, we do not use execution to intercept all, but add an annotation @ Whitelist, and the annotated methods will verify the Whitelist.
- In the aspect class, use spring's AOP annotation @ Before to declare a notification method checkWhitelist() to check the whitelist Before the Controller method is executed.
The pseudo code of section class is as follows:
@Aspect public class WhitelistAspect { @Before(value = "whitelistPointcut() && @annotation(whitelist)") public void checkAppkeyWhitelist(JoinPoint joinPoint, Whitelist whitelist) { checkWhitelist(); // Available joinPoint.getArgs() obtain Controller Method parameters // have access to whitelist Variable to get annotation parameters } @Pointcut("@annotation(com.zhenbianshu.Whitelist)") public void whitelistPointCut() { } }
Add @ Whitelist annotation on the Controller method to realize the function.
♪ expansion
In this example, the annotation is used to declare the pointcut, and I have implemented the annotation parameter to declare the whitelist to be verified. If other whitelists need to be added later, such as UID verification, uid() and other methods can be added to this annotation to realize user-defined verification.
In addition, spring's AOP also supports pointcut declaration methods such as execution (execution method), Bean (execution method of Bean object matching a specific name), and notification methods such as @ Around (executed during the execution of objective function), @ After (After the execution of method).
Thus, the function has been realized, but the leader is not satisfied = =, The reason is that AOP is used too much in the project. I suggest I change it. Well, I had to do it.
3, Interceptor
Spring's interceptor is also very appropriate to implement this function. As the name suggests, the interceptor is used to judge whether to execute this method through some parameters before the Action in the Controller is executed. To implement an interceptor, you can implement the HandlerInterceptor interface of spring.
♪ implementation
The implementation steps are as follows:
- Define the interceptor class AppkeyInterceptor class and implement the HandlerInterceptor interface.
- Implement its preHandle() method;
- Judge whether the request needs to be intercepted through annotations and parameters in the preHandle method. When intercepting the request, the interface returns false;
- Register this 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(); adopt request Get request parameters through whitelist Variable to get annotation parameters return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { // Method in Controller Execute after method execution } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // stay view Execute when the view rendering is complete } }
♪ expansion
To enable the interceptor, you need to explicitly configure it. Here, we use the WebMvcConfigurerAdapter to configure it. 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); // Interceptor enabled can be configured here path When multiple interceptors exist, any interceptor returns false Will make the subsequent request methods no longer execute } }
It should also be noted that after the interceptor is successfully executed, the response code is 200, but the response data is empty. The basic Spring Boot tutorial and sample source code can be learned here: https://github.com/javastacks/javastack , very complete.
After using the interceptor to realize the function, the leader finally made a big move: we already have an Auth parameter. The appkey can be obtained from the Auth parameter. We can take being out of the white list as a way of Auth. Why not verify it during Auth? emmm... Spitting blood.
4, ArgumentResolver
The parameter parser is a tool provided by Spring for parsing custom parameters. Our commonly used @ RequestParam annotation has its shadow. Using it, we can combine the parameters into what we want before entering the Controller Action.
Spring will maintain a ResolverList. When the request arrives, spring finds that there are custom type parameters (non basic types), and will try these resolvers in turn until a Resolver can resolve the required parameters. To implement a parameter parser, you need to implement the HandlerMethodArgumentResolver interface.
♪ implementation
- Define the user-defined parameter type AuthParam, and there are appkey related fields in the class;
- Define AuthParamResolver and implement HandlerMethodArgumentResolver interface;
- Implement the supportsParameter() interface method to adapt AuthParam to AuthParamResolver;
- Implement the resolveArgument() interface method to parse the reqest object to generate the AuthParam object, and verify the AuthParam here to confirm whether the appkey is in the white list;
- Add AuthParam parameter in the signature on the Controller Action method to enable this Resolver;
The AuthParamResolver class implemented is 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); // adopt webRequest and whitelist Verify whitelist return new AuthParam(); } } j
♪ expansion
Of course, the parameter parser also needs to be configured separately. We also configure it in WebMvcConfigurerAdapter:
@Configuration public class MvcConfiguration extends WebMvcConfigurerAdapter { @Override public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) { argumentResolvers.add(new AuthParamResolver()); } }
After this implementation, I was still a little worried, so I searched the Internet to see if there were other ways to realize this function, and found that the common one was Filter.
5, Filter
Filter is not provided by Spring. It is defined in the Servlet specification and supported by the Servlet container. Requests filtered by the filter will not be sent to the Spring container. Its implementation is also relatively simple, implementing javax Servlet. Filter interface.
Because it is not in the Spring container, the Filter cannot obtain the resources of the Spring container. It can only use the ServletRequest and ServletResponse of native Java to obtain the request parameters.
In addition, the doFilter method calling FilterChain should be displayed in a Filter, otherwise the request is considered to be intercepted. 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 { // Determine whether interception is required chain.doFilter(request, response); // The request passes the call to be displayed } @Override public void destroy() { // Called once when destroyed } }
♪ expansion
Filter also needs to display 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); // Sets the order in which filters are called return registration; } }
6, Summary
The four implementation methods have their own suitable scenarios, so what is the call order between them?
Filter is implemented by Servlet. Naturally, it is called first, and the Interceptor called later is intercepted. Naturally, it does not need to be processed later, then the parameter parser, and finally the tangent point of the section.
Click focus to learn about Huawei cloud's new technologies for the first time~