拦截器(Interceptor)是在软件开发中用于拦截和处理请求的组件。它可以在请求到达目标处理程序之前或之后进行干预和处理。
拦截器的作用包括但不限于以下几个方面:
认证和授权:拦截器可以用于验证请求的合法性和安全性,例如检查用户的身份认证信息、权限验证等。通过拦截和检查请求,可以确保只有经过认证和授权的用户才能访问特定的资源或执行特定的操作。
日志记录:拦截器可以用于记录请求和响应的日志信息,包括请求的参数、处理时间、返回结果等。通过记录日志,可以方便地进行系统监控、错误排查、性能分析和统计等工作。
异常处理:拦截器可以捕获和处理请求过程中的异常,例如参数验证失败、权限不足、请求超时等。通过拦截和处理异常,可以对异常进行统一处理和转化,返回合适的错误信息给客户端。
请求预处理和后处理:拦截器可以在请求到达目标处理程序之前进行一些预处理操作,例如参数校验、数据转换等。同时,拦截器也可以在请求处理完成后进行一些后处理操作,例如结果封装、响应头设置等。
缓存和性能优化:拦截器可以用于实现缓存机制,对一些请求进行缓存,提高系统的响应速度和性能。通过拦截请求并检查缓存,可以避免重复计算或查询数据库,减少系统的负载。
之前的拦截器代码与直接返回 Token 的方式有以下区别:
验证和认证逻辑:拦截器代码中,通过解析和验证 JWT Token,进行一系列的验证和认证逻辑,包括检查 Token 是否存在、解析 Token 中的用户角色和用户 ID、查询数据库获取账户信息、验证 Token 的有效性等。这些逻辑旨在确保请求的合法性和安全性。而直接返回 Token 的方式则省略了这些验证和认证逻辑,直接将 Token 返回给客户端。
统一处理逻辑:拦截器代码可以在请求到达目标处理程序之前拦截请求,并统一处理一些通用的逻辑,例如身份认证、权限校验、日志记录等。这样可以避免在每个请求处理程序中重复编写这些逻辑。而直接返回 Token 的方式则需要在每个请求处理程序中手动处理这些逻辑,增加了代码的重复性和维护成本。
灵活性和可扩展性:拦截器代码可以根据具体的业务需求进行扩展和定制,例如添加其他的验证规则、处理特定的业务逻辑等。而直接返回 Token 的方式则比较简单,适用于简单的无状态认证场景,但在复杂的认证授权需求下可能无法满足。
package com.wzh.springbootproject.config;
import cn.hutool.core.util.ObjectUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.wzh.springbootproject.common.Constants;
import com.wzh.springbootproject.common.ResultCodeEnum;
import com.wzh.springbootproject.common.RoleEnum;
import com.wzh.springbootproject.entity.Account;
import com.wzh.springbootproject.exception.CustomException;
import com.wzh.springbootproject.service.AdminService;
import com.wzh.springbootproject.service.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//import jakarta.servlet.http.HttpServletRequest;
//import jakarta.servlet.http.HttpServletResponse;
/**
* jwt拦截器
*/
@Component
public class JwtInterceptor implements HandlerInterceptor {
private static final Logger log = LoggerFactory.getLogger(JwtInterceptor.class);
@Resource
private AdminService adminService;
@Resource
private UserService userService;
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
// 1. 从http请求的header中获取token
String token = request.getHeader(Constants.TOKEN);
if (ObjectUtil.isEmpty(token)) {
// 如果没拿到,从参数里再拿一次
token = request.getParameter(Constants.TOKEN);
}
// 2. 开始执行认证
if (ObjectUtil.isEmpty(token)) {
throw new CustomException(ResultCodeEnum.TOKEN_INVALID_ERROR);
}
Account account = null;
try {
// 解析token获取存储的数据
String userRole = JWT.decode(token).getAudience().get(0);
String userId = userRole.split("-")[0];
String role = userRole.split("-")[1];
// 根据userId查询数据库
if (RoleEnum.ADMIN.name().equals(role)) {
account = adminService.selectById(Integer.valueOf(userId));
} else if (RoleEnum.USER.name().equals(role)) {
account = userService.selectById(Integer.valueOf(userId));
}
} catch (Exception e) {
throw new CustomException(ResultCodeEnum.TOKEN_CHECK_ERROR);
}
if (ObjectUtil.isNull(account)) {
throw new CustomException(ResultCodeEnum.USER_NOT_EXIST_ERROR);
}
try {
// 用户密码加签验证 token
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(account.getPassword())).build();
jwtVerifier.verify(token); // 验证token
} catch (JWTVerificationException e) {
throw new CustomException(ResultCodeEnum.TOKEN_CHECK_ERROR);
}
return true;
}
}
留下所需要的
package com.wzh.springbootproject.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.annotation.Resource;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Resource
private JwtInterceptor jwtInterceptor;
// 加自定义拦截器JwtInterceptor,设置拦截规则
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(jwtInterceptor).addPathPatterns("/**")
.excludePathPatterns("/")
.excludePathPatterns("/login")
.excludePathPatterns("/register")
.excludePathPatterns("/files/**");
}
}