JWT使用

JWT的认识及使用

代码:https://github.com/chenchang123abc/jwt_test.git
JWT(Json Web Token)的结构
JWT包含三部分,之间以点(.)连接

  • Header(头部)
  • Payload(负载)
  • Signature(签名)
eyJhbGciOiJIUzI1NiJ9.
eyJqdGkiOiI0ODM0YjVlZC1jODI4LTRmNmMtYTI1Ni1lMTE5NTJkZGYwYWUiLCJpYXQiOjE2MTAxMTgyMDQsImV4cCI6MTYxMDEyMTgwNCwiYWRkcmVzcyI6IuW5v-W3niIsInNleCI6MTIzLCJ1c2VyTmFtZSI6Iua1i-ivlSIsInVzZXJJZCI6MTIzfQ.
0CwxIxVVpzdQUbYAFSnHnnvo_FLJ51gtzfc0l4_uzuc

Header

Header部分是一个json对象,典型的header包含两部分:

  • alg:使用的签名算法,比如HMACSHA256或RSA
  • typ:token的类型,比如JWT
{
	"alg":"HS256",
	"typ":"JWT"
}

最后,用Base64Url将这个json对象编码后,作为JWT的第一部分

Payload

Payload部分也是json对象,用来存放数据。JWT有7个官方字段:

  • iss(issuer):签发人
  • exp(expiration time):过期时间,以秒为单位
  • iat(Issued At):签发时间,能够算出JWT的存在时间
  • nbf(Not Before):生效时间
  • jti(JWT ID):JWT的唯一标识。用来防止JWT重复
  • sub(subject):主题(很少使用)
  • aud(audience):token的受众(很少被使用)
    除了上面字段也可以自定义私有字段,比如:
{
	"userId":"1001",
	"userName":"张三"
}

最后,用Base64Url将这个json对象编码后,作为JWT的第二部分

Signature

使用Header指定的算法对Header、payload、密钥 三部分进行签名,生成的字符串作为JWT的第三部分。
比如使用HMACSHA256算法进行签名:

HMACHA256(
	Base64Url.encode(header)+"."+Base64Url.encode(payload),secret
)

签名可以用来验证数据是否被篡改,而且如果token使用私钥进行了签名,那么该签名还可以验证JWT发送者的身份。

怎么使用JWT?

客户端收到服务器返回的JWT,可以存储在Cookie里面,也可以存储在localStorage。
此后,客户端每次请求服务器,都要带上这个JWT.所以可以把他放在Cookie里面自动发送,但是这样并不能跨域,所以更好的做法是放在HTTP请求的头信息Authorization字段里面。

Authorization:Bearer<token>

另一种做法是,跨域的时候,JWT就放在POST请求的数据体里面。

JWT的特点

  1. JWT默认是不加密,但是也可以加密。
  2. JWT不加密的情况下,不能将敏感数据写入JWT (例如:密码)
  3. JWT不仅可以用于认证,也可以用于交换信息
  4. JWT最大的缺点是,由于服务器不保存session状态,因此无法在使用过程中废止某个token,或者更改token的权限。也就说,一旦签发了JWT,在到期之前就会始终有效
  5. JWT本身包含了认证信息,一旦泄密,任何人都可以获得该令牌的权限。为了减少盗用,JWT的有效期应该设置比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证
  6. 为了减少盗用,JWT不应该使用HTTP协议明码传输,要使用HTTPS协议传输

和Session-Cookie相比

Session-Cookie方式:客户端每次请求使用cookie携带session_id,服务器根据session_id区分不同的会话。
JWT方式:客户端每次请求都使用请求头携带token,服务器根据token区分不同的客户。

直接上代码操作,简单例子

引入依赖:

<!--jwt-->
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-api</artifactId>
    <version>0.10.7</version>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-impl</artifactId>
    <version>0.10.7</version>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-jackson</artifactId>
    <version>0.10.7</version>
    <scope>runtime</scope>
</dependency>
<!--jwt-->
<!--单元测试-->
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>RELEASE</version>
    <scope>compile</scope>
</dependency>
<!--单元测试-->

JWT测试例子

public class JwtTest {
    //简单的例子进行对jwt说明
    @Test
    public void JwtDemo(){
        //1.生产密钥
        String key="0123456789_0123456789_0123456789";//自定义一个字符串(字符串不能太短,不然报错)
        SecretKey secretKey=new SecretKeySpec(key.getBytes(), SignatureAlgorithm.HS256.getJcaName());

        //2.生成token
        String token= Jwts.builder()         // 创建jwt对象
                .setSubject("Json Web Token")//设置主题(声明信息)
                .signWith(secretKey)         //设置安全密钥(生产签名所需要的密钥和算法)
                .compact();                  //生成token(1.header和payload  2.生成签名 3.拼接字符串)
        System.out.println(token);

        //3.验证token
        try{
            Jwts.parser()
                    .setSigningKey(secretKey)
                    .parseClaimsJws(token);
            System.out.println("验证成功");
        }catch(Exception e)
        {
            System.out.println("验证失败");
        }

        //4.解析token
        Claims body=Jwts.parser()       //创建解析对象
                .setSigningKey(secretKey)//设置安全密钥(生成签名所需的密钥和算法)
                .parseClaimsJws(token)   //解析token
                .getBody();              //获取payload部分内容
        System.out.println("setSubject:"+body);
    }
}

创建JWT的工具类

/*
    jwt工具类
 */
public class JwtUtils {
    //key:按照签名算法的字节长度设置key
    private final static String SECRET_KEY="0123456789_0123456789_0123456789";
    //过期时间
    private final static long TOKEN_EXPIRE_MILLIS=1000*60*60;
    //创建token
    public static String createToken(Map<String,Object> claimMap){
        long currentTimeMillis=System.currentTimeMillis();
        return Jwts.builder()
                .setId(UUID.randomUUID().toString())
                .setIssuedAt(new Date(currentTimeMillis))
                .setExpiration(new Date(currentTimeMillis+TOKEN_EXPIRE_MILLIS))
                .addClaims(claimMap)
                .signWith(generateKey())
                .compact();
    }
    //验证token
    public static String verifyToken(String token){
        try{
            Jwts.parser().setSigningKey(generateKey()).parseClaimsJws(token);
            return "验证成功";
        }catch (Exception e)
        {
            e.printStackTrace();
            return "验证失败";
        }
    }
    //解析token
    public static Map<String,Object> parseToken(String token){
        return Jwts.parser()
                .setSigningKey(generateKey())
                .parseClaimsJws(token)
                .getBody();
    }
    //生成token
    public static Key generateKey(){
        return new SecretKeySpec(SECRET_KEY.getBytes(), SignatureAlgorithm.HS256.getJcaName());
    }
}

使用工具类测试:

    @Test
    public void JwtDome2(){
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("userId", 1001);
        map.put("userName", "张三");
        map.put("age",20);
        String token = JwtUtils.createToken(map);
        System.out.println(token);
        }

token:

eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4YWQwMThmNS05NWU1LTQ5NzEtYjZhMi1lNTQ1Y2EzYTM4YmYiLCJpYXQiOjE2MTAxNjY4ODMsImV4cCI6MTYxMDE3MDQ4MywidXNlck5hbWUiOiLlvKDkuIkiLCJ1c2VySWQiOjEwMDEsImFnZSI6MjB9.7fDzkHZ8NTfEwtSasXa0xyp-7zBFfkGFmeKA84OAni0
    @Test
    public void JwtDome2(){
//        Map<String, Object> map = new HashMap<String, Object>();
//        map.put("userId", 1001);
//        map.put("userName", "张三");
//        map.put("age",20);
//        String token = JwtUtils.createToken(map);
//        System.out.println(token);
        //eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4YWQwMThmNS05NWU1LTQ5NzEtYjZhMi1lNTQ1Y2EzYTM4YmYiLCJpYXQiOjE2MTAxNjY4ODMsImV4cCI6MTYxMDE3MDQ4MywidXNlck5hbWUiOiLlvKDkuIkiLCJ1c2VySWQiOjEwMDEsImFnZSI6MjB9.7fDzkHZ8NTfEwtSasXa0xyp-7zBFfkGFmeKA84OAni0

        String token="eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4YWQwMThmNS05NWU1LTQ5NzEtYjZhMi1lNTQ1Y2EzYTM4YmYiLCJpYXQiOjE2MTAxNjY4ODMsImV4cCI6MTYxMDE3MDQ4MywidXNlck5hbWUiOiLlvKDkuIkiLCJ1c2VySWQiOjEwMDEsImFnZSI6MjB9.7fDzkHZ8NTfEwtSasXa0xyp-7zBFfkGFmeKA84OAni0";
        String result = JwtUtils.verifyToken(token);
        System.out.println(result);
        Map<String,Object> map=JwtUtils.parseToken(token);
        System.out.println(map);
    }

输出结果:

验证成功
{jti=8ad018f5-95e5-4971-b6a2-e545ca3a38bf, iat=1610166883, exp=1610170483, userName=张三, userId=1001, age=20}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值