JWT(java web token)

2022-11-18 11:45:02 浏览数 (1)

# 引言

# https

网络传输的安全性

必须有安全认证

# cookie

浏览器可以不用cookie

浏览器默认发送cookie

tomcat session活化技术,关闭后会把session序列化存储本地文件,启动时加载

# 简介

  1. 是跨语言的,原则上任何web都支持
  2. 适合分布式
  3. 可以做验证,支持加密算法
  4. 缺点是不能更新有效时间

# 数据结构

  1. 没有换行的
  2. 使用.分隔成3部分:标头Header、载荷payload、签名signature,base64编码,eg:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyTmFtZSI6IueuoeeQhuWRmCIsImV4cCI6MTY2NzQ0MjYxNSwidXNlcklkIjoiYWRtaW4ifQ.MaAgsYMWc05nMddmJrI1qmbvm5IXTV54hG7IKQJOvDw

Base64 编码/解码 | 菜鸟工具 (runoob.com) (opens new window)

# Header

{”alg”:“HS256”,“typ”:“JWT”}

# Payload

自定义

代码语言:javascript复制
iss:
exp:
sub: 主题
aud:
nbf: 在此之前不可用
iat:
jti:

复制代码

不要再此存储敏感信息

实际上一般与redis联用

# signature

密钥不要改

# JWT的种类

typ属性

  1. nonsecure JWT:未经过签名,不安全的JWT
  2. JWS: 经过签名的jwt

公钥: 验证jwt是否合法(解密),是公开的(可能同时多人持有)。 私钥: 生成jwt使用(加密),通常个人保存私钥 公钥与私钥都能用于加密和解密,看实际用途

JWS,也就是WT Signature,其结构就是在之前nonsecure JWT的基础上,在头部声明签名算法,并在最后添加上签名。创建签名,是保证jwt不能被他人随意篡改。我们通常使用的WT一般都是WS为了完成签名,除了用到neaderf信息和payload信息外,还需要算法的密钥,也就是secretKey。加密的算法一般有2类: 对称加密:secretKey指加密密钥,可以生成签名与验签非对称加密:secretKey:指私钥,只用来生成签名,不能用来验签(验签用的是公钥) JWT的密钥或者密钥对,一般统一称为SON Web Key,也就是WK到目前为止,jw的签名算法有三种:

  1. HMAC【哈希消息验证码(对称)】:HS256/HS384/HS512
  2. RSASSA【RSA签名算法(非对称)】(RS256/RS384/RS512)
  3. ECDSA【椭圆曲线数据签名算法(非对称)】(ES256/ES384/ES512)

在线生成私钥公钥 https://www.ssleye.com/ssltool/pass_double.html (opens new window)

# 代码

# 依赖

推荐java-jwt

代码语言:javascript复制
<dependency>
  <groupId>com.auth0</groupId>
  <artifactId>java-jwt</artifactId>
  <version>3.19.2</version>
</dependency>

代码语言:javascript复制
package com.zr;

import static org.junit.Assert.assertTrue;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.junit.Test;

import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;

/**
 * Unit test for simple App.
 */
public class AppTest 
{

    private String token="eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyTmFtZSI6IueuoeeQhuWRmCIsImV4cCI6MTY2NzQ0MzUzOCwidXNlcklkIjoiYWRtaW4ifQ.83pbDb22U4EgfKWNeVLQh6AU4mBSTsNBva0eJqE1_WU";

    public static void main(String[] args) {
        AppTest appTest = new AppTest();
        appTest.testJWT();
        appTest.verifierToken();

    }

    @Test
    public void testJWT() {
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.SECOND, 180);
        //header部分,使用map,自动转json
        Map<String, Object> header = new HashMap<>();
        //加密算法,对称加密
        header.put("alg", "HS256");
        header.put("typ", "JWT");
        String token = JWT.create()
                .withHeader(header)
                //载荷部分,自定义
                .withClaim("userId","admin")
                .withClaim("userName", "管理员")
                //签名过期时间,180秒后过期
                .withExpiresAt(calendar.getTime())
                //签名加密算法
                .sign(Algorithm.HMAC256("mima123456!"));
        System.out.println(token);
        this.token = token;
    }

    @Test
    public void verifierToken(){
        //获取校验对象
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256("mima123456!")).build();
        try{
            //校验token
            DecodedJWT decodedJWT= jwtVerifier.verify(this.token);
            //校验通过获取载荷部分
            Claim userId = decodedJWT.getClaim("userId");
            Claim userName = decodedJWT.getClaim("userName");
            System.out.println(userId.asString());
            System.out.println(userName.asString());
            System.out.println(decodedJWT.getExpiresAt());
        }catch (TokenExpiredException e){
            System.out.println("token过期: "  e.getMessage());
        }catch (SignatureVerificationException e){
            System.out.println("token非法: "  e.getMessage());
        }catch (Exception e){
            System.out.println(e.getMessage());
        }

    }
}

# 非对称加密

例如:rsa256算法

代码语言:javascript复制
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.8.9</version>
</dependency> 

代码语言:javascript复制
public static String getTokenRsa(Map<String,String> payload){
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DATE,7);
        JWTCreator.Builder builder = JWT.create();
        payload.forEach((k,v) -> builder.withClaim(k,v));
        RSA rsa = new RSA(RSA_PRIVATE_KEY, null);
        RSAPrivateKey privateKey= (RSAPrivateKey) rsa.getPrivateKey();
        String token = builder.withExpiresAt(calendar.getTime()).sign(Algorithm.RSA256(null,privateKey));
        return token;
    }

    public void decodeRsa(String token){
        RSA rsa = new RSA(null, RSA_PUBLIC_KEY);
        RSAPublicKey publicKey=(RSAPublicKey)rsa.getPublicKey();
        JWTVerifier jwtVerifier = JWT.require(Algorithm.RSA256(publicKey,null)).build();
        try{
            //校验token
            DecodedJWT decodedJWT= jwtVerifier.verify(token);
            //校验通过获取载荷部分
            Claim userId = decodedJWT.getClaim("userId");
            Claim userName = decodedJWT.getClaim("userName");
            System.out.println(userId.asString());
            System.out.println(userName.asString());
            System.out.println(decodedJWT.getExpiresAt());
        }catch (TokenExpiredException e){
            System.out.println("token过期: "  e.getMessage());
        }catch (SignatureVerificationException e){
            System.out.println("token非法: "  e.getMessage());
        }catch (Exception e){
            System.out.println(e.getMessage());
        }

    }

0 人点赞