摘要:在实际项目中,可以根据需要选择使用过滤器或拦截器来实现JWT认证。过滤器适用于全局性的请求和响应处理,而拦截器则更适用于框架内部的请求处理。两者各有优缺点,具体选择取决于项目的需求和架构。
第一步:添加jwt和fastjson的依赖
<!--jwt-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<!--JSON-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.76</version>
</dependency>
第二步:编写生成和解析JWT令牌的工具类
相关代码和注释如下
package com.example.jwttest.jwtUtils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
import java.util.Map;
public class jwtUtils {
//创建jwt
public static String getJwt(Map<String, Object> claims){
String jwt = Jwts.builder()//创建jwt的方法
.addClaims(claims)//存放相关信息,通过参数传入
.setExpiration(new Date(System.currentTimeMillis() + 43200000L))//设置过期时长
.signWith(SignatureAlgorithm.HS256,"test")//前者是加密方式,后者是token的密钥
.compact();
return jwt;//返回生成的jwt令牌
}
//解析jwt
public static Claims parseJwt(String jwt){
Claims claims = Jwts.parser()//解析jwt的方法
.setSigningKey("test")//通过密钥获取token
.parseClaimsJws(jwt)
.getBody();
return claims;
}
}
第三步:编写过滤器或拦截器
过滤器实现Filter接口,拦截器通常有两个类,一个同过滤器类似的解析token的接口,实现的是
HandlerInterceptor接口,还有一个类是配置类,可以定义需要拦截的路径和不需要拦截的路径;
它们都遵循如下步骤:
过滤器的相关代码和注释
import com.example.jwttest.Result.Result;
import com.example.jwttest.jwtUtils.jwtUtils;
import org.springframework.util.StringUtils;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebFilter(urlPatterns = "/*")//过滤的路径
public class filter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;//需要强转为HttpServlet
HttpServletResponse response = (HttpServletResponse) servletResponse;
//获取请求路径
String url = request.getRequestURL().toString();
//1.含有login的路径放行
if (url.contains("login")){
filterChain.doFilter(request,response);
return;
}
//2.获取请求头中的token
String header = request.getHeader("test");
//判断token是否为null或者是空字符串
if (!StringUtils.hasLength(header)){
Result result = Result.error("未登录");
//转json格式返回错误信息给客户端
String jsonString = JSONObject.toJSONString(result);
response.setContentType("application/json;charset=utf-8");
response.getWriter().write(jsonString);
return;
}
//3.解析token
try {
jwtUtils.parseJwt(header);
} catch (Exception e) {
Result result = Result.error("未登录");
String jsonString = JSONObject.toJSONString(result);
response.setContentType("application/json;charset=utf-8");
response.getWriter().write(jsonString);
return;
}
//4.放行
filterChain.doFilter(request,response);
}
补充:为什么要强转为 HttpServletRequest和HttpServletResponse?因为ServletRequest中只提供了获取基本信息的方法,没有获取用户请求类型的方法。filter过滤器它在Servlet规范中定义,因此是Java EE标准的一部分,拦截器HandlerInterceptor是SpringMVC提供的。
拦截器的相关代码和注释
拦截器
package com.example.jwttest.Interceptor;
import com.alibaba.fastjson.JSONObject;
import com.example.jwttest.Result.Result;
import com.example.jwttest.jwtUtils.jwtUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class Interceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//获取请求路径
String url = request.getRequestURL().toString();
//获取请求头
String header = request.getHeader("test");
//判断请求头是否为空字符串或null
if (!StringUtils.hasLength(header)){
Result result = Result.error("未登录");
//因为前端是json数据,要将返回信息通过阿里巴巴的fastjson转为json格式
String jsonString = JSONObject.toJSONString(result);
response.setContentType("application/json;charset=utf-8");
response.getWriter().write(jsonString);
return false;
}
//用jwt工具类解析token,
try {
jwtUtils.parseJwt(header);
} catch (Exception e) {
Result result = Result.error("未登录");
String jsonString = JSONObject.toJSONString(result);
response.setContentType("application/json;charset=utf-8");
response.getWriter().write(jsonString);
return false;
}
//所有通过再放行
return true;
}
}
配置类 实现 WebMvcConfigurer接口
package com.example.jwttest.Webconfig;
import com.example.jwttest.Interceptor.Interceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class config implements WebMvcConfigurer {
@Autowired
private Interceptor interceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(interceptor)
.addPathPatterns("/**")//拦截全部路径
.excludePathPatterns("/login");//不拦截的路径
}
}
总结:在现实中使用拦截器居多。拦截器用return实现拦截和放行,可以直接配置类中设置想拦截的路径和不想拦截的路径。过滤器拦截与放行通过dofilter方法,拦截器更灵活方便。过滤器范围更广。