package com.template.back.server.interceptor; import cn.hutool.core.util.ObjectUtil; import com.alibaba.fastjson.JSON; import com.template.back.common.pojo.system.Admin; import com.template.back.common.utils.AdminThreadLocal; import com.template.back.common.utils.NoAuthorization; import com.template.back.common.vo.R; import com.template.back.server.service.system.AdminService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import org.springframework.util.AntPathMatcher; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * @author 张骞 * @version 1.2 * 验证后台用户登录的拦截器,并且将用户信息写入AdminThreadLocal */ @Component //注解加载到spring容器中 @Slf4j //日志注解 public class AdminLoginInterceptor implements HandlerInterceptor { //knife4j框架的doc文档地址开关 @Value("${doc-interceptor-state}") private Boolean docState; //注入业务层对象,用来验证用户登录信息 @Autowired private AdminService adminService; //创建路径匹配器对象 private static final AntPathMatcher PATH_MATCHER = new AntPathMatcher(); //注入redis模板类,用于每次验证写入用户登录信息 @Autowired private RedisTemplate redisTemplate; private static String sessionId = null; /** * 请求的前置处理,将User对象写入到ThreadLocal中 * * @param request * @param response * @param handler * @return * @throws Exception */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //00.获取sessionId sessionId = request.getSession().getId(); //01.获取本次请求的URI String url = request.getRequestURI(); log.info("拦截到请求:{}", url); //将Admin对象写入到ThreadLocal中 //校验当前的Handler if (!(handler instanceof HandlerMethod)) { return true; } //判断当前请求是否添加了NoAuthorization注解,如果添加了就跳过验证 if (((HandlerMethod) handler).hasMethodAnnotation(NoAuthorization.class)) { return true; } if (handler instanceof HandlerMethod) { HandlerMethod handlerMethod = (HandlerMethod) handler; NoAuthorization noAnnotation = handlerMethod.getMethod().getAnnotation(NoAuthorization.class); if (noAnnotation != null) { // 如果该方法被标记为无需验证登录,直接返回即可 return true; } } //2-3.对knife4j框架 String[] docUrls = new String[]{ "/doc.html", //从这里开始,是swagger框架过滤使用 "/webjars/**", "/swagger-resources", "/v2/api-docs" }; //2-3-2使用私有方法进行请求匹配 Boolean docCheck = this.check(docUrls, url); //2-3-3如果不需要,则直接放行 if (docCheck) { log.info("拦截到knife4j请求{}", url); //判断配置文件的状态,如果为true,则放行,否则不放行 if(docState){ return true; }else { //如果配置文件为false,则始终返回false return false; } } //2-4.判断本次请求, 是否需要登录, 才可以访问 //2-4-1定义需要过滤的数组 String[] urls = new String[]{ "/system/user/login", "/system/user/logout", "/backend/**", "/common/**", "/upload/**", "/backend/pages/login/login.html", "/", "error.jsp", "*.js", "*.css" }; //2-4-2使用私有方法进行请求匹配 Boolean check = this.check(urls, url); //2-4-3如果不需要,则直接放行 if (check) { log.info("本次请求{}不需要进行登录拦截", url); return true; } //01.从session中拿到当前登录的用户数据 Admin admin = (Admin) request.getSession().getAttribute("admin"); //02.验证数据是否为空,如果不为空,则在数据库中查询用户信息 if(ObjectUtil.isNotEmpty(admin)){ //调用业务层验证的方法 if(null != admin.getAdminId() || null != admin.getUserName() || null!= admin.getPassword()){ Admin admin1 = this.adminService.findAdminById(admin.getAdminId(),admin.getUserName(),admin.getPassword()); if(null != admin1){ //用户验证成功,写入数据 AdminThreadLocal.set(admin1); //04-3-2重新写入session,为session延时 request.getSession().setAttribute("admin", admin); log.info("过滤器层返回数据:后台用户校验成功!"); return true; } } } //03用户状态验证失败,返回到登录页面 // response.sendRedirect(request.getContextPath() + "/backend/pages/login/login.html"); response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN"))); log.error("过滤器层返回数据:用户登录验证失败!"); return false; } /** * 请求结束的后置处理,将User对象从ThreadLocal中删除 * @param request * @param response * @param handler * @param ex * @throws Exception */ @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { //将User对象从ThreadLocal中删除 AdminThreadLocal.remove(); //把登录状态信息从redis中删除 } /** * 路径匹配,检查本次请求是否需要放行 * * @param urls * @param uri * @return */ private Boolean check(String[] urls, String uri) { //01.遍历要放行的请求集合 for (String url : urls) { //02.调用请求匹配器的方法 boolean match = PATH_MATCHER.match(url, uri); //03.如果匹配,返回true if (match) { return true; } } //04.如果不匹配,返回false return false; } }