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.
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
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
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)
Test other interfaces, if the token is not passed, it will be intercepted
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!