Home  >  Article  >  Java  >  How SpringBoot implements login interception through ThreadLocal

How SpringBoot implements login interception through ThreadLocal

WBOY
WBOYforward
2023-05-22 12:04:421309browse

    1 Preface

    Registration and login can be said to be the most common thing in daily development, but generally after entering the company, functions like this have long been available Development is complete, unless it is a new project. In the past two days, I happened to encounter such a need to complete the registration and login function on the PC side.

    There are many ways to achieve such a requirement: like

    1) HandlerInterceptor WebMvcConfigurer ThreadLocal

    2) Filter filter

    3) Security Framework Shiro ( Lightweight framework)

    4) Security framework Spring Securety (heavyweight framework)

    And I use the first Spring HandlerInterceptor WebMvcConfigurer ThreadLocal technology to implement it.

    2 Concrete class

    2.1HandlerInterceptor

    HandlerInterceptor is the interface provided for interceptors in springMVC. It is similar to the filter Filter in Servlet development and is used for preprocessing by the processor. For processing and post-processing, three methods need to be rewritten.

    preHandle:

    Calling time: before controller method processing

    Execution order: In the case of chained Intercepter, the Intercepters are executed one after another in the order of declaration

    If false is returned, execution will be interrupted. Note: it will not enter afterCompletion

    postHandle:

    Calling premise: preHandle returns true

    Calling time: After the Controller method is processed, DispatcherServlet Before rendering the view, that is to say, you can operate ModelAndView in this method.

    Execution order: In the case of chained Interceptor, the Intercepter is executed in the order of declaration.

    Remarks: Although postHandle starts with post , but both post requests and get requests can be processed

    afterCompletion:

    Calling premise: preHandle returns true

    Calling time: after DispatcherServlet renders the view

    Mostly used to clean up resources

    2.2WebMvcConfigurer

    WebMvcConfigurer configuration class is actually an internal configuration method of Spring, using the form of JavaBean instead The traditional xml configuration file format is customized for the framework. Some Handlers, Interceptors, ViewResolvers, and MessageConverters can be customized. For spring mvc configuration based on java-based method, you need to create a configuration class and implement the WebMvcConfigurer interface;

    in Spring Boot 1.5 version relies on rewriting the method of WebMvcConfigurerAdapter to add custom interception converter, message converter, etc. After SpringBoot 2.0 version, this class has been marked @Deprecated (deprecated). The official recommendation is to directly implement WebMvcConfigurer or directly inherit WebMvcConfigurationSupport. The first method is to implement the WebMvcConfigurer interface (recommended), and the second method is to inherit the WebMvcConfigurationSupport class

    3 Code practice

    1) Write the interceptor HeadTokenInterceptor so that it inherits HandlerInterceptor

    package com.liubujun.config;
    import com.liubujun.moudle.UserToken;
    import com.liubujun.util.SecurityContextUtil;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.http.HttpStatus;
    import org.springframework.stereotype.Component;
    import org.springframework.util.StringUtils;
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.xml.ws.handler.Handler;
    import java.io.IOException;
    /**
     * @Author: liubujun
     * @Date: 2022/5/21 16:12
     */
    @Component
    @Slf4j
    public class HeadTokenInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            String authorization = request.getHeader("Authorization");
            if (authorization == null ) {
                unauthorized(response);
                return false;
            }
            //这里一般都会解析出userToken的值,这里为了方便就直接new了
            UserToken userToken  = new UserToken();
            SecurityContextUtil.addUser(userToken);
            return false;
        }
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        }
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            SecurityContextUtil.removeUser();
        }
        private void unauthorized(HttpServletResponse response) {
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            try {
                response.getWriter().append(HttpStatus.UNAUTHORIZED.getReasonPhrase());
            } catch (IOException e) {
                log.error("HttpServletResponse writer error.msg",HttpStatus.UNAUTHORIZED.getReasonPhrase());
                log.error(e.getMessage(),e);
            }
        }
    }

    2) Write MyWebMvcConfigurer to inherit WebMvcConfigurationSupport

    package com.liubujun.config;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    import java.util.ArrayList;
    /**
     * @Author: liubujun
     * @Date: 2022/5/21 16:40
     */
    @Configuration
    public class MyWebMvcConfigurer extends WebMvcConfigurationSupport {
        @Autowired
        private HeadTokenInterceptor headTokenInterceptor;
        /**
         * 类似于白名单,在这边添加的请求不会走拦截器
         * @param registry
         */
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            ArrayList<String> pattres = new ArrayList<>();
            pattres.add("/login/login");
            registry.addInterceptor(headTokenInterceptor).excludePathPatterns(pattres).addPathPatterns("/**");
            super.addInterceptors(registry);
        }
        /**
         * 添加静态资源
         * @param registry
         */
        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
            registry.addResourceHandler("xxx.html")
                    .addResourceLocations("classpath:/META-INF/resources");
            super.addResourceHandlers(registry);
        }
    }

    3) Write the ThreadLocal class to store user information

    package com.liubujun.util;
    import com.liubujun.moudle.UserToken;
    import org.springframework.core.NamedThreadLocal;
    /**
     * @Author: liubujun
     * @Date: 2022/5/23 9:41
     */
    public class SecurityContextUtil {
        private static ThreadLocal<UserToken> threadLocal = new NamedThreadLocal<>("user");
        public static void addUser(UserToken user){
            threadLocal.set(user);
        }
        public static UserToken getUser(){
            return threadLocal.get();
        }
        public static void removeUser(){
            threadLocal.remove();
        }
        public static String getPhoneNumber(){
            return threadLocal.get().getPhoneNumber();
        }
        public static Integer getId(){
            return threadLocal.get().getId();
        }
        public static String getUserText(){
            return threadLocal.get().getUserText();
        }
    }

    4) Write a test controller

    @RestController
    @RequestMapping(value = "/login",produces = {"application/json;charset=UTF-8"})
    public class Login {
        @PostMapping("/login")
        public String login(){
            return "登录请求不需要拦截";
        }
        @PostMapping("/other")
        public String other(){
            return "其他的请求需要拦截";
        }
    }

    5) Test

    Test the login interface, (lead directly without passing the token)

    How SpringBoot implements login interception through ThreadLocal

    Test other interfaces, if the token is not passed, it will be intercepted

    How SpringBoot implements login interception through ThreadLocal

    The above is the detailed content of How SpringBoot implements login interception through ThreadLocal. For more information, please follow other related articles on the PHP Chinese website!

    Statement:
    This article is reproduced at:yisu.com. If there is any infringement, please contact admin@php.cn delete