package com.interceptor; import java.io.IOException; import java.io.PrintWriter; import java.util.HashMap; import java.util.Map; import com.alibaba.fastjson.JSONObject; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.http.HttpStatus; import com.annotation.IgnoreAuth; import com.entity.EIException; import com.entity.TokenEntity; import com.service.TokenService; import com.utils.R; /** * 权限(Token)验证拦截器 * * 核心职责:实现基于Token的用户认证和权限验证 * * 功能特性: * 1. Token验证:验证用户Token的有效性 * 2. 跨域支持:处理跨域请求和OPTIONS预检请求 * 3. 注解支持:通过@IgnoreAuth注解跳过验证 * 4. 会话管理:将用户信息存入Session * 5. 统一响应:标准化的错误响应格式 * * 技术实现: * - Spring MVC拦截器 * - 注解驱动配置 * - FastJSON序列化 * - 会话管理 */ @Component // 声明为Spring组件,由容器管理 public class AuthorizationInterceptor implements HandlerInterceptor { // Token在请求头中的键名 public static final String LOGIN_TOKEN_KEY = "Token"; @Autowired private TokenService tokenService; /** * 预处理方法,在控制器方法执行前调用 * * @param request HTTP请求对象 * @param response HTTP响应对象 * @param handler 处理器对象 * @return 是否继续执行后续处理 * @throws Exception 处理过程中可能抛出的异常 */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 支持跨域请求 - 设置CORS响应头 response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE"); response.setHeader("Access-Control-Max-Age", "3600"); // 预检请求缓存时间 response.setHeader("Access-Control-Allow-Credentials", "true"); // 允许携带凭证 response.setHeader("Access-Control-Allow-Headers", "x-requested-with,request-source,Token, Origin,imgType, Content-Type, cache-control,postman-token,Cookie, Accept,authorization"); response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin")); // 允许的源 // 跨域时会首先发送一个OPTIONS请求,这里我们给OPTIONS请求直接返回正常状态 if (request.getMethod().equals(RequestMethod.OPTIONS.name())) { response.setStatus(HttpStatus.OK.value()); // 返回200状态码 return false; // 不继续执行后续处理 } // 检查处理器方法上的@IgnoreAuth注解 IgnoreAuth annotation; if (handler instanceof HandlerMethod) { // 获取方法上的@IgnoreAuth注解 annotation = ((HandlerMethod) handler).getMethodAnnotation(IgnoreAuth.class); } else { // 如果不是HandlerMethod(如资源处理器),直接放行 return true; } // 从header中获取token String token = request.getHeader(LOGIN_TOKEN_KEY); /** * 不需要验证权限的方法直接放过 */ if(annotation != null) { return true; // 有@IgnoreAuth注解,跳过Token验证 } // Token验证逻辑 TokenEntity tokenEntity = null; if(StringUtils.isNotBlank(token)) { // 通过TokenService验证Token有效性 tokenEntity = tokenService.getTokenEntity(token); } // 如果Token有效 if(tokenEntity != null) { // 将用户信息存入Session,供后续使用 request.getSession().setAttribute("userId", tokenEntity.getUserid()); // 用户ID request.getSession().setAttribute("role", tokenEntity.getRole()); // 用户角色 request.getSession().setAttribute("tableName", tokenEntity.getTablename()); // 用户表名 request.getSession().setAttribute("username", tokenEntity.getUsername()); // 用户名 return true; // 验证通过,继续执行 } // Token无效或未提供Token,返回未授权错误 PrintWriter writer = null; response.setCharacterEncoding("UTF-8"); // 设置响应编码 response.setContentType("application/json; charset=utf-8"); // 设置响应类型 try { writer = response.getWriter(); // 返回JSON格式的错误响应 writer.print(JSONObject.toJSONString(R.error(401, "请先登录"))); } finally { // 确保Writer正确关闭 if(writer != null){ writer.close(); } } // 也可以选择抛出异常的方式(注释掉的代码) // throw new EIException("请先登录", 401); return false; // 验证失败,中断请求处理 } // 可以添加的增强方法: /** * 获取当前登录用户ID * * @param request HTTP请求 * @return 用户ID,如果未登录返回null */ public static Long getUserId(HttpServletRequest request) { Object userId = request.getSession().getAttribute("userId"); return userId != null ? (Long) userId : null; } /** * 获取当前登录用户角色 * * @param request HTTP请求 * @return 用户角色,如果未登录返回null */ public static String getRole(HttpServletRequest request) { Object role = request.getSession().getAttribute("role"); return role != null ? (String) role : null; } /** * 获取当前登录用户名 * * @param request HTTP请求 * @return 用户名,如果未登录返回null */ public static String getUsername(HttpServletRequest request) { Object username = request.getSession().getAttribute("username"); return username != null ? (String) username : null; } /** * 检查当前用户是否具有指定角色 * * @param request HTTP请求 * @param role 要检查的角色 * @return 是否具有指定角色 */ public static boolean hasRole(HttpServletRequest request, String role) { String currentRole = getRole(request); return currentRole != null && currentRole.equals(role); } /** * 检查当前用户是否已登录 * * @param request HTTP请求 * @return 是否已登录 */ public static boolean isLogin(HttpServletRequest request) { return getUserId(request) != null; } /** * 后处理方法(可选实现) */ @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // 请求完成后的清理工作,如记录日志等 } }