Spring拦截器实现鉴权的示例代码
作者:Zayn~
什么是拦截器?
拦截器(Interceptor)类似于Servlet中的过滤器,主要用于拦截用户请求并做出相应的处理,例如拦截器可以进行权限验证、记录请求信息的日志、判断用户是否登录等。拦截器允许自定义预处理(Pre-Processing),在其中可以选择禁止对应Handler 的执行;也允许自定义后处理(Post-Precessing);
怎样实现Spring拦截器?
实现Spring拦截器很简单,只需要实现HandlerInterceptor接口即可。HandlerInterceptor这个接口中有三个核心方法:
1.preHandle方法:在HandlerMapping确定Handler对象之后,但在HandlerAdapter调用handler之前执行(就是在调用controller之前执行该方法)。该方法返回一个布尔值,只有true的时候才继续执行对应的handler,否则不再执行对应的handler了。
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return true; }
2.postHandle方法:在 HandlerAdapter 实际调用处理程序之后,但在 DispatcherServlet 呈现视图之前调用(就是在响应返回客户端之前执行)。
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {}
3.afterCompletion方法:请求处理完成后回调,即渲染视图后。将在处理程序执行的任何结果上被调用,从而允许适当的资源清理。注意:只有当这个拦截器的 preHandle 方法成功完成并返回 true 时才会被调用!与 postHandle 方法一样,该方法将以相反的顺序在链中的每个拦截器上调用,因此第一个拦截器将是最后一个被调用的。
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {} }
关于上述三个核心方法调用的顺序,在此我们假设有是三个拦截器,Interceptor1 、Interceptor2、和Interceptor3。在定义三个拦截器的时候我们就是按照这个顺序定义的,而拦截器的执行顺序就是按照之前定义的顺序执行。
Interceptor1的preHandle方法 -> Interceptor2的preHandle方法 -> Interceptor3的preHandle方法 -> controller ->Interceptor3 的postHandle方法 -> Interceptor2 的postHandle方法 -> Interceptor1 的postHandle方法 -> Interceptor3 的afterCompletion方法 -> Interceptor2 的afterCompletion方法 ->Interceptor1 的afterCompletion方法。如图:
如何使用Spring拦截器鉴权?
通过上述对三个核心方法的解释可知,如果我们想通过拦截器实现鉴权,那么只需要实现接口后,在preHandle方法中做相应的处理即可。如下:
public class SecurityInterceptor implements HandlerInterceptor { @Autowired private JddPmsHelper jddPmsHelper; @Value("${global.authTest}") private String authTest; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //测试环境不校验权限,需预发验证 if ("true".equals(authTest)) { return true; } String uri = request.getRequestURI(); if (uri.contains("static")) { return true; } String pin = ServletUtils.getCommonPin(); if (StringUtils.isBlank(pin)) { throw new NoLoginException("未登陆"); } if (uri.equals("/")) { return true; } boolean checkResult = jddPmsHelper.authCheckUrl(pin, uri); if (!checkResult) { throw new NoneSecurityException("您没有权限访问,请联系管理员,对您的erp账号进行配置"); } return true; } @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 { } }
在实现HandlerInterceptor接口之后,可以通过
1、拦截器注册:实现WebMvcConfigurer的addInterceptors注册。
/** * 拦截器注册 WebConfig * */ @Configuration @Slf4j public class WebConfig implements WebMvcConfigurer { /** * 登录/权限拦截器 */ @Resource private CombinedLoginInterceptor combinedLoginInterceptor; /** * 控制层切面处理 * ControllerExceptionHandler */ @Resource private ControllerExceptionResolver controllerExceptionResolver; /** * */ private static final String MATCH_ALL = "/**"; /** * 免验证 */ private static final String APP_EXCLUDE = "/common/info"; /** * 异常页 */ private static final String ERROR_URL = "/error"; /** * 无需权限验证的URI集合 */ private static final String[] PC_WHITE_LIST = {APP_EXCLUDE, ERROR_URL}; @Override public void addInterceptors(InterceptorRegistry registry) { //PC端登录拦截,必须添加 registry.addInterceptor(combinedLoginInterceptor).addPathPatterns(MATCH_ALL).excludePathPatterns(PC_WHITE_LIST).order(1); } @Override public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) { resolvers.add(controllerExceptionResolver); } }
2、通过XML文件注册
<!-- 单点登录拦截器配置--> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="com.xxx.intercepter.SecurityInterceptor"/> </mvc:interceptor> </mvc:interceptors>
除了使用拦截器鉴权,还可以有哪几种方式?
1、传统AOP方式:在Controller方法前添加切点,然后再对切点进行处理即可。
2、过滤器:其实现相对简单,只需要实现Filter接口即可。
详细实现可以参考这篇文章: SpringBoot 项目鉴权的 4 种方式
到此这篇关于Spring拦截器实现鉴权的示例代码的文章就介绍到这了,更多相关Spring拦截器鉴权内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!