拦截器原理
在 Spring MVC 中,拦截器(Interceptor)是一种机制,用于拦截请求并在处理程序(Controller)执行之前或之后执行一些操作。拦截器允许您在请求的不同阶段(如处理程序执行前、处理程序执行后、视图渲染前、视图渲染后等)添加自定义逻辑。
其中问号就是拦截器处理的范围。
实现自定义拦截器
@Component public class SampleInterceptor implements HandlerInterceptor { // 在controller执行前的逻辑 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 在controller执行之前执行的逻辑 System.out.println("Pre-handle logic"); return true; // 返回 true,将允许请求继续传递到处理程序; //返回 false,将阻止请求传递给处理程序 } // 在controller执行后、并在视图渲染前执行的逻辑 @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("Post-handle logic"); } //在服务器响应结束后执行的逻辑 @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("After-completion logic"); } }
将自定义拦截器添加到SpringMvc中
@Configuration public class InterceptorRoll implements WebMvcConfigurer { @Autowired LoginTicketInterceptor loginTicketInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { //registry.addInterceptor() 方法可以向注册表中添加拦截器。 InterceptorRegistration interceptorRegistration = registry.addInterceptor(loginTicketInterceptor); //添加拦截器生效路径,以及拦截器忽略的路径 ... } }
使用拦截器实现权限验证逻辑
关键鉴权逻辑图解:
1.在请求controller之前先经过拦截器,从cookie中获取用户标识,根据用户标识,从redis中取出登录凭证
2.如果登录凭证有效,则设置一个线程与用户信息进行绑定,并将用户信息存入到视图模型中
3.如果凭证无效则跳转到登录页面
4.在用户请求完之后,销毁线程与用户名的绑定
实现:
1.创建工具类ThreadHolder
package com.duhong.util; import com.duhong.entity.User; import org.springframework.data.redis.core.StringRedisTemplate; public class ThreadHolder { static ThreadLocal<User> users=new ThreadLocal<>(); /** * 设置线程信息 * @param user */ public static void setHolder(User user){ users.set(user); } /** * 获取当前线程的信息 * @return */ public static User getHolder(){ return users.get(); } /** * 解除线程与当前用户的绑定 */ public static void remove(){ users.remove(); } }
2.创建自定义拦截器
@Component public class LoginTicketInterceptor implements HandlerInterceptor { @Autowired StringRedisTemplate redisTemplate;//redis客户端 @Autowired UserMapper userMapper;//根据用户id查询用户所有信息 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //获取用户的cookie Cookie[] cookies = request.getCookies(); String loginOwner=null; System.out.println("开始鉴权"); for(Cookie cookie:cookies){ if(cookie.getName().equals("loginOwner")){ loginOwner=cookie.getValue(); break; }; } LoginTicket ticket=new LoginTicket(); //如果loginOwner不等于null,从redis中获取登录签证 if(loginOwner!=null) { String s = redisTemplate.opsForValue().get(RedisUtil.getTicket(loginOwner)); ticket = RedisUtil.getObject(s); //用户已被授权 if (ticket != null && ticket.getStatus() == 1) { User user = userMapper.selectById(ticket.getUserId()); //将用户信息与当前线程绑定 ThreadHolder.setHolder(user); return true; } } //如果签证不等于null,而且签证的状态无效则跳转到登录页面 response.sendRedirect("/site/login"); return false; } /** * 在视图层渲染之前将用户信息存入模型 * @param request * @param response * @param handler * @param modelAndView * @throws Exception */ public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception { if(ThreadHolder.getHolder()!=null&&modelAndView!=null){ //从当前线程中获取用用户信息 modelAndView.addObject("loginUser",ThreadHolder.getHolder()); } } /** * 在服务器响应完本次信息之后,解除当前线程与用户信息的绑定 * @param request * @param response * @param handler * @param ex * @throws Exception */ public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception { ThreadHolder.remove(); } }
3.将拦截器加入到SpringMvc中并设置拦截规则
package com.duhong.config; import com.duhong.filter.LoginTicketInterceptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import java.util.Arrays; import java.util.List; @Configuration public class InterceptorRoll implements WebMvcConfigurer { @Autowired LoginTicketInterceptor loginTicketInterceptor; //配置文件中配置配置需要过滤的路径形式为:路径,路径,... @Value("${allow.pages}") String allowPages; @Override public void addInterceptors(InterceptorRegistry registry) { InterceptorRegistration interceptorRegistration = registry.addInterceptor(loginTicketInterceptor); interceptorRegistration.addPathPatterns("/**"); String[] split = allowPages.split(","); for (String allowpage : split) { System.out.println(allowpage); //忽略指定页面 interceptorRegistration.excludePathPatterns(allowpage); } //忽略静态资源 interceptorRegistration.excludePathPatterns("/css/**","/img/**","/js/**"); } }
如有收获,就点个赞吧!