JWT的基础介绍

前言

JWT主要是用于用户登录鉴权,传统的方法就是session认证。

http是无状态的协议,当有用户向系统使用账户名称和密码进行用户认证之后,下一次请求还要再一次用户认证才行。因为我们不能通过http协议知道是哪个用户发出的请求,所以如果要知道是哪个用户发出的请求,那就需要在服务器保存一份用户信息(保存至session),然后在认证成功后返回cookie值传递给浏览器,那么用户在下一次请求时就可以带上cookie值,服务器就可以识别是哪个用户发送的请求,是否已认证,是否登录过期等等。

session认证的缺点其实很明显,由于session是保存在服务器里,所以如果分布式部署应用的话,会出现session不能共享的问题,很难扩展。

JWT的介绍

JWT:Json Web Token 它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。

 流程:

  • 用户使用账号、密码登录应用,登录的请求发送到Authentication Server。
  • Authentication Server进行用户验证,然后创建JWT字符串返回给客户端。
  • 客户端请求接口时,在请求头带上JWT。
  • Application Server验证JWT合法性,如果合法则继续调用应用接口返回结果

用户信息是保存在客户端,关键在于生成JWT和解析JWT。

JWT的数据结构

JWT一般是这样的字符串,分为三个部分,以"."隔开。

xxxxx.yyyyy.zzzzz

Header:第一部分是头部分,描述JWT元数据的Json对象

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

 alg属性表示签名使用的算法,默认为HMAC SHA256(写为HS256),typ属性表示令牌的类型,JWT令牌统一写为JWT。最后,使用Base64 URL算法将上述JSON对象转换为字符串保存。

Payload:第二部分是Payload,也是一个Json对象,除了包含需要传递的数据,还有七个默认的字段供选择。

分别是,iss:发行人、exp:到期时间、sub:主题、aud:用户、nbf:在此之前不可用、iat:发布时间、jti:JWT ID用于标识该JWT。

如果自定义字段,可以这样定义:

{
    //默认字段
    "sub":"主题123",
    //自定义字段
    "name":"java技术爱好者",
    "isAdmin":"true",
    "loginTime":"2021-12-05 12:00:03"
}

JSON对象也使用Base64 URL算法转换为字符串保存。

Signature:第三部分是签名。是这样生成的,首先需要指定一个secret,该secret仅仅保存在服务器中,保证不能让其他用户知道。然后使用Header指定的算法对Header和Payload进行计算,然后就得出一个签名哈希。

JWT的优点:

  • json格式的通用性,所以JWT可以跨语言支持,比如Java、JavaScript、PHP、Node等等。
  • 可以利用Payload存储一些非敏感的信息。
  • 便于传输,JWT结构简单,字节占用小。
  • 不需要在服务端保存会话信息,易于应用的扩展。

使用JWT 

导入依赖

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>

创建工具类,用于创建jwt字符串和解析jwt


import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;

import java.util.Date;

/**
 *
 * @description JWT:令牌token生成
 */
public class TokenUtil {

    // token有效期
    private static final long EXPIRATION = 86400L;//1day = 86400L

    /**
     *
     * @description 创建token工具方法
     */
    public static String createToken(User user) {
        JwtBuilder builder = Jwts.builder();
        builder.setAudience(user.getUserCode()) // 这个user.getUserCode()是我后续需要的参数
                .setIssuer("xxx")
                .claim("userId", user.getId()) // userId 是我自己后续需要的参数,这个根据自己的需求进行设置
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION * 1000));
        String accessToken = builder.compact();
        return accessToken;
    }

    /**
     * 
     * @description 验证token返回用户code
     */
    public static String validateToken(String token) {
        Claims claims = Jwts.parserBuilder().build().parseClaimsJwt(token).getBody();
        String userCode = claims.getAudience();
        return userCode;
    }

    /**
     * 
     * @description 验证token返回用户ID
     */
    public static String getUserIdFromToken(String token) {
        Claims claims = Jwts.parserBuilder().build().parseClaimsJwt(token).getBody();
        String userId = claims.get("userId", String.class);
        return userId;
    }
}

有些微修改,我这里没有使用到第三部分。
链接:https://www.zhihu.com/question/485758060/answer/2257869896

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值