JWT学习并测试简单的token解密与加密

1,623 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

JWT的全称为Json Web Token,它可以帮助消息在Web层安全传递。 抛弃以前的cookie和session,jwt最重要的一个特点是无状态 以前是cookie存在客户端本地,sessionid存储在服务器,同时寄生于cookie。 前者存在不安全性,可能存在cookie欺骗工具,后者若是小数据还好说,若是大数据,则加大了服务器的压力。 至此,token它诞生了。它比较与cookie有如下一些优点

  • 支持跨域访问,将token置于请求头中,而cookie是不支持跨域访问的;
  • 无状态化,服务端无需存储token,只需要验证token信息是否正确即可,而session需要在服务端存储,一般是通过cookie中的sessionID在服务端查找对应的session;
  • 无需绑定到一个特殊的身份验证方案(传统的用户名密码登陆),只需要生成的token是符合我们预期设定的即可;
  • 避免CSRF跨站伪造攻击,是因为它不依赖于cookie;
  • .......

首先我们来谈谈JWT的组成吧 它是由header(消息头)payload(载荷)signature(签名) 三部分组成

1、header头部主要是包含以下一些信息:

  • 主要采用的key-value来阐述信息
  • typ:代表是消息体类型,这里指的是JWT
  • alg:采用的加密算法,默认是HS256(HMAC-SHA256),当然你可以指定其他类型的算法

2、payload主体主要是包含以下一些信息:

  • payload是存在需要发送的数据,可以支持自定义数据,当然也是有如下默认数据可以填入
  • iss (issuer):签发人
  • exp (expiration time):过期时间
  • sub (subject):主题
  • aud (audience):受众
  • nbf (Not Before):生效时间
  • iat (Issued At):签发时间
  • jti (JWT ID):编号

你也可以自定义为

{
	“name”:xxx	,
	“age”:xxx
}

3、signature代表是签名:

  • 签名是根据你设置的秘钥和加密算法来进行加密的

好的,理论说完了,我们开始来一个实战吧

请在你的maven下加入下面配置信息

		<!--单元测试-->
        <groupId>junit</groupId>
    	<artifactId>junit</artifactId>
    	<version>4.12</version>

        <!--lombok 注解式开发-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.16</version>
        </dependency>

		<!--JWT 包-->
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.4.1</version>
        </dependency>

上面我用到了lombok注解开发,如果你没有接触过lombok,你需要去插件商店下载lombok,如下 在这里插入图片描述 我的包结构如下(实际只用到下面贴出代码的三个class) 在这里插入图片描述

/*TokenUtils.java*/
package com.ysj.pojo;
import com.auth0.jwt.*;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@SuppressWarnings("all")
public class TokenUtils {
    // 设置过期时间为30分钟
    private static final long EXPIRATION_TIME = 30*60*1000;

    // 设置加密字符串,要足够复杂足够乱
    private static final String SECRET_KEY = "<sda122D4dD4AS5SF894FS5>?sd!@21fDADsdadgrhdfop";

    // 根据token来 生成一个加密的token字符串
    public String getToken(Token token){
        // 设置过期时间
        Date lastDate = new Date(System.currentTimeMillis() + EXPIRATION_TIME);
        // 选择算法
        Algorithm algorithm = Algorithm.HMAC256(SECRET_KEY);
        // 设置header
        Map<String,Object> header = new HashMap<>();
        header.put("typ","JWT");
        header.put("alg","HS256");

        // 生成token
        return JWT.create()
                .withHeader(header)
                .withClaim("userid",token.getUserid())
                .withClaim("name",token.getName())
                .withClaim("age",token.getAge())
                .withClaim("lastTime",token.getLastTime())
                .withExpiresAt(lastDate)
                .sign(algorithm);
    }

    // 获取token数据
    public Token getTokenData(String tokenString){

        // 对token的加密字符串进行解密
        DecodedJWT jwt = JWT.decode(tokenString);

        // 通过Token类的建造者模式来实例化类,注意builder是一个静态方法
        Token token = Token.builder()
             .userid(jwt.getClaim("userid").asString())
             .name(jwt.getClaim("name").asString())
             .age(jwt.getClaim("age").asInt())
             .lastTime(jwt.getClaim("lastTime").asDate()).build();
        return token;
    }

    // 创建一个token
    public String createToken(String userid,String name,int age){

        // 创建初始时间日期
        Date date = new Date();

        Token token = Token.builder()
                .userid(userid)
                .name(name)
                .age(age)
                .lastTime(date)
                .build();
        return this.getToken(token);

    }

}

/*Token.java*/
package com.ysj.pojo;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder()
public class Token {
    private String userid;
    private String name;
    private int age;
    private Date lastTime;
}

下面是测试类

package com.ysj.testPackage;

import com.ysj.pojo.Token;
import com.ysj.pojo.TokenUtils;
import org.junit.jupiter.api.Test;


public class testToken {

    @Test
    public void testTokenOperation(){
        TokenUtils tokenUtils = new TokenUtils();

        String tokenString = tokenUtils.createToken("ysj66666","凌寒天",20);
        System.out.println("------生成token-----------\n"+tokenString);
        Token tokenData = tokenUtils.getTokenData(tokenString);
        System.out.println("------获取token数据-----------\n"+tokenData.toString());
    }
}

输出如下 在这里插入图片描述 加密字符串是以. 进行分割的,总共有三部分 (header,payload,signature) ,所以有三个点,每个点对应一个加密字符串。 服务端用秘钥进行对加密字符串的解密,获取用户信息并返回。 这就是简单的token加密与解密测试。 在这里插入图片描述