如何简单创建JWT令牌和过滤器和拦截器

24 年 3 月 24 日 星期日 (已编辑)
900 字
5 分钟

摘要

在实际项目中,可以根据需要选择使用过滤器或拦截器来实现JWT认证。过滤器适用于全局性的请求和响应处理,而拦截器则更适用于框架内部的请求处理。两者各有优缺点,具体选择取决于项目的需求和架构。

第一步:添加 JWT 和 FastJson 的依赖

xml
<!--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 令牌的工具类

java
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 接口。
  • 还有一个类是配置类,可以定义需要拦截的路径和不需要拦截的路径。

它们都遵循如下步骤:

过滤器的相关代码和注释

java
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提供的。

拦截器的相关代码和注释

拦截器

java
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;
   }
}

配置类 实现 WebMvcConfiger接口

java
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方法,拦截器更灵活方便。过滤器范围更广。

文章标题:如何简单创建JWT令牌和过滤器和拦截器

文章作者:Yosoo

文章链接:https://yosoo.wang/posts/2024-07/jwt-token-interceptor[复制]

最后修改时间:


商业转载请联系站长获得授权,非商业转载请注明本文出处及文章链接,您可以自由地在任何媒体以任何形式复制和分发作品,也可以修改和创作,但是分发衍生作品时必须采用相同的许可协议。
本文采用CC BY-NC-SA 4.0进行许可。