SpringBoot is a quick way to set up the interceptor and implement permission validation

  • 2020-12-21 18:02:57
  • OfStack

1. An overview of the

Interceptors are increasingly being used, especially with the popularity of slicing oriented programming. So what can interceptors usually do?

We mentioned earlier in the Agent introduction that statistical functions take time to call. This idea is exactly the same as AOP's wrap enhancement.

Generally speaking, the scenario is as follows:

Function enhancement: such as parameter checking for a function, or result filtering, etc. You can even authenticate to functions. Performance monitoring: Statistics function performance. Log dot: For example, before the user logs in to a function, dot statistics such as PV.

And so on and so forth.

2. Spring's interceptor

In both SpringMVC and SpringBoot, the interceptor has to be mentioned:
org.springframework.web.servlet.handler.HandlerInterceptorAdapter


public abstract class HandlerInterceptorAdapter implements AsyncHandlerInterceptor {

  //  Execute before the target method executes 
  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    return true;
  }

  //  Execute after the target method executes, but before the request returns, we can still apply the  ModelAndView modified 
  @Override
  public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) 
             throws Exception {}

  //  Executes after the request has been returned 
  @Override
  public void afterCompletion(
      HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
      throws Exception {}

  //  Used to handle asynchronous requests ,  when Controller A method is triggered when an asynchronous request is made in 
  @Override
  public void afterConcurrentHandlingStarted(
      HttpServletRequest request, HttpServletResponse response, Object handler)
      throws Exception {}
}

3. Implement an interceptor for verifying simple permissions

1. Customize 1 permission annotation @Auth


@Inherited
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Auth {
  String user() default "";
}
Inherited: When using this custom annotation, if the annotation is on top of the class, the subclass inherits the annotation automatically. Otherwise, the subclass does not inherit the annotation. Keep in mind that annotations declared with Inherited are valid only when used on a class, not for methods, attributes, etc. Target: Indicates where this annotation can be placed. Common places are: TYPE= on enumerations or annotations, FIELD= on fields, METHOD= on methods, PARAMETER= on function parameter lists, CONSTRUCTOR= on constructors, LOCAL_VARIABLE= on local variables, and so on. Retention: Life cycle of this annotation. Common: SOURCE= source period; CLASS= Bytecode period (compiled); RUNTIME= runtime, which is usually used more often. Documentd: Generate annotated documentation.

2. Add annotations to Controller's methods

After adding the annotations in step 1, add them to the method you are using, as follows.


@RestController
@EnableAutoConfiguration
public class DemoController {

  @Auth(user = "admin")
  @RequestMapping(value = "/hello", method = RequestMethod.GET)
  public String sayHello() {
    return "hello world.";
  }
}

3. Implement interceptor function

Requirement: We verify the user when he /hello is accessed by URI. If it is admin, it will be released; otherwise, it will be refused, assuming that the user's identity is in the URL parameter.

Idea: So we want to validate the user before we execute sayHello(). Release if its identity is the same as that in the annotation. So we're going to do it in preHandle().

Difficulty: How do we get the @Auth annotation on the Controller method? Looking at the three parameters of PreHandle(), it seems that none of them can provide annotations in the Controller class.

In fact, the third parameter handler, 1 cases whose type is: org. springframework. web. method. HandlerMethod type, which contains information of annotation.

Why do you say that?

In SpringBoot, the default type of annotations is at the function level, while in SpringMVC the default type is at the Controller object level.

Therefore, if in SpringMVC you need to configure in ES93en-ES94en.xml:
< bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/ > , so that its type is HandlerMethod.

Let's take a look at the concrete implementation logic:


  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    System.out.println("preHandle");
    if (!handler.getClass().isAssignableFrom(HandlerMethod.class)) {
      System.out.println("cat cast handler to HandlerMethod.class");
      return true;
    }
    //  To obtain annotations 
    Auth auth = ((HandlerMethod) handler).getMethod().getAnnotation(Auth.class);
    if (auth == null) {
      System.out.println("cant find @Auth in this uri:" + request.getRequestURI());
      return true;
    }
    //  Take the user identity from the parameter and verify it 
    String admin = auth.user();
    if (!admin.equals(request.getParameter("user"))) {
      System.out.println("permission denied");
      response.setStatus(403);
      return false;
    }
    return true;
  }

The implementation logic is really about two things: retrieving identities from parameters and comparing them to annotations.

4. Configure interceptors

So how do you make this interceptor work?

At this point, we need to configure WebMvcConfigurerAdapter

Specific implementation is as follows:


@Configuration
public class ConfigAdapter extends WebMvcConfigurerAdapter {
  @Override
  public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/hello");
  }
}

Note: There are two things to note here. One is the @Configuration annotation so that the SpringBoot service can discover this configuration. The other one is a configuration match, and this is intercepting the "/hello" one. ("/**" is for all access intercepts)

4. Run

Visit http: / / 127.0.0.1:8080 / hello & # 63; user=admin and you can see the results.

Details of the code in this article: https: / / github com/hawkingfoo/springboot - interceptor


Related articles: