java JJWT

本文详细介绍了JWT(JSON Web Token)的工作原理,包括其组成部分:头部、载荷和签名,以及如何在SpringBoot中生成和解析JWT。示例代码展示了如何设置JWT的过期时间、载荷信息,并使用HS256算法进行签名。此外,还提供了JWT的签名算法选择和一个完整的JWT token生成及解析的Demo。
摘要由CSDN通过智能技术生成

实际上就是一个字符串:

由三部分组成

(1)头部 - header:

描述该JWT的最基本的信息,如:类型(即JWT)以及签名所用算法

{
    "alg": "HS256",
    "typ": "JWT"
}

typ:类型
alg:签名的算法,上边使用的算法是HS256

会对头部进行 BASE64编码,编码格式如下:

dsHHKLjklljLKJ678jklHJKjhJK657hjk

(2)载荷 - payload

存放有效信息的地方。

分三部分

        标准声明:

iss:    该JWT的签发者
sub: jwt所面向的用户
aud: 接收jwt的一方
exp: jwt过期时间,必须大于签发时间
nbf:  定义在什么时间之前,该jwt是不可用的
iat:   jwt的签发时间

         公共声明:一般存放用户的信息。

        私有声明:提供者和消费者共同定义的声明。

(3)签名 - secret 保证jwt安全性的唯一部分

jwt的第三部分,是一个签证信息,这个签证信息有三部分组成:

1> header (base64后的header)
2> payload(base64后的payload)
3> secret (盐一定要保密)

三者组成之后进行加密,三部分以点分割。

注意:secret是保存在都服务器上的,jwt的签发生成也是在服务器上,secret就是用来进行jwt的签发和jwt的验证,所以,它就是你的服务端的私钥,在任何场景下都不能泄露出去,一旦客户端得知这个secret那就意味着客户端也可以签单jwt了。

sringboot 使用jwt

生成token

第一步:安装依赖 

(提示:如果你的java版本为最新版本,使用jjwt旧版,在生成token是会抛出异常,大致错误找不到类,此时需要下载最新版jjwt)

<!--jwt依赖-->
<!--新版本-->
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-api</artifactId>
    <version>0.11.1</version>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-impl</artifactId>
    <version>0.11.1</version>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-jackson</artifactId> <!-- or jjwt-gson if Gson is preferred -->
    <version>0.11.1</version>
    <scope>runtime</scope>
</dependency>

第二步: 构建jwt对象,生成token

public class TokenTest {
    public static void main(String[] args) {
        String userId = "18";
        // 生成 secret密钥
        // SecretKey key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
        // String scretString = Encoders.BASE64.encode(key.getEncoded());
        String scretString = "WAGFd+7X2q1evBcU2p+IEDzuR39SXyoNn0UlnntpnLg=";
        System.out.println("1:"+scretString);
        // 构建jwt
        JwtBuilder jwtBuilder = Jwts.builder()
                // jti
                .setId(userId)
                // sub 签发给谁
                .setSubject("rose")
                // iat 签发时间
                .setIssuedAt(new Date())
                .signWith(SignatureAlgorithm.HS256, scretString); // 签名
        // 根据对象生成 令牌 token
        String token = jwtBuilder.compact();
        System.out.println(token);
    }
}

 结果如下:

 关于签名算法,很多种:

一个完整的token 生成及解析demo:

package com.lxc.springboot.controller;

import com.alibaba.fastjson.JSONObject;
import io.jsonwebtoken.*;
import io.jsonwebtoken.io.DeserializationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;


public class TokenTest {
    static Logger log = LoggerFactory.getLogger(TokenTest.class);
    public static void main(String[] args) {

        String token = "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoi5ZCV5pif6L6wIiwiYWdlIjoyMywiaWF0IjoxNjI2MjUxOTg5LCJqdGkiOiIxMCIsInN1YiI6InJvc2UiLCJleHAiOjE2MjY4NTY3ODl9.z3dO5x2r0xjBNgboAOncUQ7-acrl4cucd2JziFVQUB0";
        // 解析token
        parseToken(token);

        // 生成token
        // System.out.println(generateToken());
    }

    /**
     * 生成token
     * @return void
     */
    static public String generateToken() {
        // 有效期默认7天
        Long time = 1000 * 60 * 60 * 24 * 7L;
        // 用户的id
        String userId = "10";
        // 存储的用户的信息 - 不建议把用户信息全部存到token里。
        Map<String, Object> userInfo = new HashMap<>();
        userInfo.put("name", "吕星辰");
        userInfo.put("age", 23);
        return generateToken(userId, userInfo, time);
    }


    /**
     * 生成token
     * @param userId
     * @param claims
     * @param time
     * @return string
     */
    static public String generateToken(String userId, Map<String, Object> claims, Long time) {
        // 生成 secret密钥
        // SecretKey key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
        // String scretString = Encoders.BASE64.encode(key.getEncoded());

        // 这里其实就是new一个JwtBuilder,设置jwt的body
        JwtBuilder jwtBuilder = Jwts.builder()
                // 自定义用户的一些信息, 必须放最前面,不然后面设置的东西都会没有:如setExpiration会没有时间 !!!
                .setClaims(claims)
                // iat 签发时间
                .setIssuedAt(getIssuedAt())
                // 设置jti(JWT ID):是JWT的唯一标识,根据业务需要,这个可以设置为一个不重复的值,主要用来作为一次性token,从而回避重放攻击。
                .setId(userId)
                // sub 签发给谁
                .setSubject("rose")
                // 设置过期时间
                .setExpiration(getExpiration(time))
                .signWith(SignatureAlgorithm.HS256, getSecretKey()); // 签名

        // 根据对象生成 令牌 token
        return jwtBuilder.compact();
    }


    /**
     * 解析token
     * @param token
     */
    static public void parseToken(String token) throws DeserializationException {
        String msg = null;
        try{
            Claims claims = Jwts.parserBuilder()
                    .setSigningKey(getSecretKey()) // 拿到签名时的秘钥
                    .build()
                    .parseClaimsJws(token)
                    .getBody();

            // claims就是一个map
            // {"name":"吕星辰","age":23,"iat":1626251989,"jti":"10","sub":"rose","exp":1626856789}
            System.out.println(JSONObject.toJSONString(claims));
            System.out.println(claims.getId()); // 获取id
            System.out.println(claims.getIssuedAt()); // 获取签发时间
            System.out.println(claims.getSubject()); // 获取签收人
            System.out.println(claims.getExpiration()); // 获取过期时间
            System.out.println(claims.get("name")); // 获取用户 name
            System.out.println(claims.get("age")); // 获取用户 age
        }catch (SignatureException se) {
            msg = "密钥错误";
            log.error(msg, se);
        }catch (MalformedJwtException me) {
            msg = "密钥算法,或者密钥转换错误,或者token不正确";
            log.error(msg, me);

        }catch (MissingClaimException mce) {
            msg = "密钥缺少校验数据";
            log.error(msg, mce);

        }catch (ExpiredJwtException mce) {
            msg = "token已过期";
            log.error(msg, mce);

        }catch (JwtException jwte) {
            msg = "密钥解析错误";
            log.error(msg, jwte);
        }
    }


    /**
     * 获取密钥 这个可以在资源配置文件中定义
     * @return string
     */
    static private String getSecretKey() {
        return "WAGFd+7X2q1evBcU2p+IEDzuR39SXyoNn0UlnntpnLg=";
    }


    /**
     * 设置过期时间
     * @param time
     * @return Date
     */
    static private Date getExpiration(Long time) {
        // 把时间戳转化为Date时间格式
        // System.currentTimeMillis() + time 【当前时间 + 传进来的时间 = 过期时间】
        return new Date(System.currentTimeMillis() + time);
    }


    /**
     * 签发时间 - 默认为当前时间
     * @return date
     */
    static private Date getIssuedAt() {
        return getIssuedAt(new Date());
    }
    static private Date getIssuedAt(Date date) {
        return date;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值