java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > SpringBoot整合JWT生成token与验证

SpringBoot整合JWT(JSON Web Token)生成token与验证的流程及示例

作者:辛苦cv的小hui

JSON Web Token(JWT)是一种开放的标准(RFC 7519),定义了一种紧凑的、自包含的方式来安全地在各方之间传输信息作为JSON对象,这篇文章主要给大家介绍了关于SpringBoot整合JWT(JSON Web Token)生成token与验证的相关资料,需要的朋友可以参考下

JWT

什么是JWT

JWT(JSON Web Token)是是目前最流行的跨域认证解决方案。它通常被用于对用户进行身份验证和授权。JWT由三部分组成,每个部分之间使用"."进行分隔,这三部分分别是:

官网地址:https://jwt.io/introduction

JWT使用流程

确定要传递的信息:

生成JWT:

JWT传输:

客户端保存JWT:

客户端发送JWT:

服务器验证JWT:

服务器响应:

通过以上流程,JWT实现了一种安全、紧凑、自包含的令牌传递机制,用于在客户端和服务器之间安全地传输用户信息。

springboot引入jwt相关依赖

要在Spring Boot项目中引入jjwt,你需要在你的pom.xml(如果你使用Maven)或build.gradle(如果你使用Gradle)文件中添加相应的依赖。

maven:

<!--引入jwt相关包来生成token-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-api</artifactId>
            <version>0.11.2</version>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-impl</artifactId>
            <version>0.11.2</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-jackson</artifactId>
            <version>0.11.2</version>
            <scope>runtime</scope>
        </dependency>

Gradle:

dependencies {  
    implementation 'io.jsonwebtoken:jjwt-api:0.11.2' 
    runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.2'   
    runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.2' 
}

Token的使用示例:

工具类

先写一个创建Token的方法,再写一个验证token的方法

import com.certificateManage.common.R;
import com.certificateManage.controller.exception.TokenException;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import io.jsonwebtoken.security.SignatureException;

import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Date;

//用于生成token的类
public class JwtTokenUtil {

    private static final String SECRET_KEY = "abcdefgabcdefghijklmnopqrstuvwxyz"; // 密钥
    private static final SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;//加密方式
    //ttMillis是token持续时间
    public static String createToken(String id, long ttlMillis) {
        // 签名密钥
        byte[] secretKeyBytes = SECRET_KEY.getBytes(StandardCharsets.UTF_8);
        SecretKeySpec secretKeySpec = new SecretKeySpec(secretKeyBytes, signatureAlgorithm.getJcaName());

        // 设置JWT的签发时间和过期时间
        Date now = new Date();
        Date expiration = new Date(now.getTime() + ttlMillis);
        // 使用指定的密钥和算法生成JWT
        return Jwts.builder()
                .setSubject(id)//设置id
                .setIssuedAt(now) // 设置签发时间
                .setExpiration(expiration) // 设置过期时间
                .signWith(secretKeySpec,signatureAlgorithm) // 设置签名密钥和签名算法
                .compact(); // 生成JWT字符串
    }


    //验证token如果正确返回用户id
    public static R checkToken(String token){
        try {
            // 解析token  
            Claims claims = Jwts.parser()
                    .setSigningKey(Keys.hmacShaKeyFor(SECRET_KEY.getBytes(StandardCharsets.UTF_8))) // 设置密钥  
                    .parseClaimsJws(token) // 解析token  
                    .getBody(); // 获取负载  

            // 验证负载中的信息  
            String subject = claims.getSubject(); // 获取用户ID或其他信息  
            Date expiration = claims.getExpiration(); // 获取过期时间  
            System.out.println(expiration.toString());

            // 验证token是否过期  
            if (expiration.before(new Date())) {
                throw new TokenException("token失效");
            }
            return R.success(subject);

        } catch (ExpiredJwtException e) {
            // 当token过期时,会捕获到ExpiredJwtException异常  
            return R.error("Token已过期");
        } catch (UnsupportedJwtException e) {
            // 当token不受支持时,会捕获到UnsupportedJwtException异常  
            return R.error("Token不受支持");
        } catch (MalformedJwtException e) {
            // 当token格式错误时,会捕获到MalformedJwtException异常  
            return R.error("Token格式错误");
        } catch (SignatureException e) {
            // 当token签名错误时,会捕获到SignatureException异常  
            return R.error("Token签名错误");
        } catch (IllegalArgumentException e) {
            // 当token为空或非法时,会捕获到IllegalArgumentException异常  
            return R.error("Token为空或非法");
        } catch (TokenException e) {
            // 处理TokenException  
            return R.error("Token验证失败: " + e.getMessage());
        } catch (Exception e) {
            // 处理其他异常  
            return R.error("发生未知错误: " + e.getMessage());
        }
    }
}
// TokenException类,用于处理与Token相关的异常  
public class TokenException extends Exception {  
    public TokenException(String message) {  
        super(message);  
    }  
}  
}

R结果集

创建一个R结果集用来封装结果

//统一返回为结果集R   1为成功,0为失败
public class R<T>  {

    private Integer code; //编码:1成功,0和其它数字为失败
    private String msg; //错误信息
    private T data; //数据

    //静态方法返回成功时候,R的属性
    public static <T> R<T> success(T object) {
        R<T> r = new R<>();
        r.data = object;
        r.code = 1;
        return r;
    }

    //静态方法返回失败时传入消息
    public static <T> R error(String msg) {
        R r = new R();
        r.msg = msg;
        r.code = 0;
        return r;
    }
    // getter和setter方法省略...  
}

返回一个生成的token

在用户发送登录请求后如果验证通过就返回一个生成的token

 String token=JwtTokenUtil.createToken(String.valueOf(user.getId()),3600000L);//生成token返回前端
 return R.success(token);

接下来就是拦截所有请求并且验证响应头的token是否正确

线程工具类

在每次请求时在当前线程进行存储信息

public class BaseContext {
    // 使用ThreadLocal来存储用户ID
    private static final ThreadLocal<String> userIdThreadLocal = new ThreadLocal<>();

    // 设置用户ID
    public static void setUserId(String userId) {
        userIdThreadLocal.set(userId);
    }

    // 获取用户ID
    public static String getUserId() {
        return userIdThreadLocal.get();
    }

    // 清除用户ID(通常在请求处理完毕后调用)
    public static void clearUserId() {
        userIdThreadLocal.remove();
    }
}

创建拦截器

import com.certificateManage.common.BaseContext;
import com.certificateManage.common.R;
import com.certificateManage.util.tokenUtil.JwtTokenUtil;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class JwtInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 从请求头中获取JWT
        String token = request.getHeader("Authorization");
        if ("OPTIONS".equalsIgnoreCase(request.getMethod())){
            System.out.println("OPTIONS请求,放行");
            return true;
        }
        if (token == null || !token.startsWith("Bearer ")) {
            // 如果没有JWT或者格式不正确,返回错误
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "token令牌不存在或请求头格式错误");
            return false;
        }
        // 去除"Bearer "前缀,获取真正的JWT
        token = token.substring(7);

        try {
            // 验证JWT
            R r=JwtTokenUtil.checkToken(token);
            // JWT验证成功,继续处理请求
            if (r.getCode()==1) {
                // 将用户ID存储在ThreadLocal中
                BaseContext.setUserId(String.valueOf(r.getData()));
                return true;
            }else {
                // JWT验证失败,返回错误
                response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Token验证失败");
                return false;
            }
        } catch (Exception e) {
            // JWT验证失败,返回错误
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Token验证失败");
            return false;
        }
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 在请求处理完毕后清除用户ID
        BaseContext.clearUserId();
    }
}

这样就可以在每次请求验证Token,并把token中存储的用户id存到当前线程.方便我们对发送请求的用户进行操作

总结

到此这篇关于SpringBoot整合JWT(JSON Web Token)生成token与验证的文章就介绍到这了,更多相关SpringBoot整合JWT生成token与验证内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文