JWT(Json Web Token)原理

本文详细介绍了JWT(JSON Web Token)的认证流程,包括客户端与服务器间的交互过程,以及JWT的组成部分:头部、有效载荷和签名。同时,提供了JWT工具类的实现代码和使用示例,帮助读者理解如何在实际项目中应用JWT。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原理图解

  • JWT流程

    1. 客户端向服务器发起登陆请求,post登陆数据
    2. 服务端验证身份,将用户标识符打包生成 JWT, 并且返回给客户端
    3. 客户端发起获取用户资料请求,把刚刚拿到的 JWT 一起发送给服务器
    4. 服务器发现数据中有 JWT ,进行验证
    5. 服务器返回该用户的用户资料
  • JWT分析

    1. 头部 Header

      头部有两部分信息,形式如下:

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

      alg: 声明加密的算法

      typ: 声明类型

      然后对该json进行base64编码,成为Header

    2. 有效载荷 Payload

      该部分有三种声明,分别是registered,public,private。形式同上。

      • Registered claims : 这里有一组预定义的声明,它们不是强制的,但是推荐。JWT指定七个默认字段供选择。

      iss:发行人

      exp:到期时间

      sup:主题

      aud:用户

      nbf:在此之前不可用

      iat:发行时间

      jti:JWT ID用于标识该JWT

      • Public claims : 可以随意定义。
      • Private claims : 用于在同意使用它们的各方之间共享信息,并且不是注册的或公开的声明。

      然后对该json进行base64编码,成为Payload

    3. 签名 Signature

      签名是对上面两部分数据签名,通过指定的算法生成哈希,以确保数据不会被篡改。操作如下:

      HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
      

      在计算出签名后,将JWT头部,有效载荷和签名的三个部分组合成一个字符串,每个部分用"."分隔,就构成整个JWT对象了。

  • 实例

    1. 引入maven依赖

      <dependency>
      	<groupId>com.auth0</groupId>
          <artifactId>java-jwt</artifactId>
          <version>3.2.0</version>
      </dependency>
      <dependency>
          <groupId>io.jsonwebtoken</groupId>
          <artifactId>jjwt</artifactId>
          <version>0.7.0</version>
      </dependency>
      
    2. 编写JWT工具类

      public class JwtUtils {
          /**
           * 签发JWT
           * @param id
           * @param subject 可以是JSON数据 尽可能少
           * @param ttlMillis
           * @return  String
           *
           */
          public static String createJWT(String id, String subject, long ttlMillis) {
              SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
              long nowMillis = System.currentTimeMillis();
              Date now = new Date(nowMillis);
              SecretKey secretKey = generalKey();
              JwtBuilder builder = Jwts.builder()
                      .setId(id)
                      .setSubject(subject)   // 主题
                      .setIssuer("user")     // 签发者
                      .setIssuedAt(now)      // 签发时间
                      .signWith(signatureAlgorithm, secretKey); // 签名算法以及密匙
              if (ttlMillis >= 0) {
                  long expMillis = nowMillis + ttlMillis;
                  Date expDate = new Date(expMillis);
                  builder.setExpiration(expDate); // 过期时间
              }
              return builder.compact();
          }
          /**
           * 验证JWT
           * @param jwtStr
           * @return
           */
          public static CheckResult validateJWT(String jwtStr) {
              CheckResult checkResult = new CheckResult();
              Claims claims = null;
              try {
                  claims = parseJWT(jwtStr);
                  checkResult.setSuccess(true);
                  checkResult.setClaims(claims);
              } catch (ExpiredJwtException e) {
                  checkResult.setErrCode(SystemConstant.JWT_ERRCODE_EXPIRE);
                  checkResult.setSuccess(false);
              } catch (SignatureException e) {
                  checkResult.setErrCode(SystemConstant.JWT_ERRCODE_FAIL);
                  checkResult.setSuccess(false);
              } catch (Exception e) {
                  checkResult.setErrCode(SystemConstant.JWT_ERRCODE_FAIL);
                  checkResult.setSuccess(false);
              }
              return checkResult;
          }
          public static SecretKey generalKey() {
              byte[] encodedKey = Base64.decode(SystemConstant.JWT_SECERT);
              SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
              return key;
          }
          
          /**
           * 
           * 解析JWT字符串
           * @param jwt
           * @return
           * @throws Exception
           */
          public static Claims parseJWT(String jwt) throws Exception {
              SecretKey secretKey = generalKey();
              return Jwts.parser()
                  .setSigningKey(secretKey)
                  .parseClaimsJws(jwt)
                  .getBody();
          }
      }
      
    3. 使用(测试例子)

      public class LoginController {
          @Autowired
          UserRepository userRepository;
          
          @ApiOperation(value="用户登陆")
          @RequestMapping(value="login",method = RequestMethod.POST)
          public ReturnVo login(String username, String password,HttpServletResponse
                  response) {
              User user =  userRepository.findByUsername(username);
              if(user!=null){
                  if(user.getPassword().equals(password)){
                      //把token返回给客户端-->客户端保存至cookie-->客户端每次请求附带cookie参数
                      String JWT = JwtUtils.createJWT("1", username, SystemConstant.JWT_TTL);
                      return ReturnVo.ok(JWT);
                  }else{
                      return ReturnVo.error();
                  }
              }else{
                  return ReturnVo.error();
              }
          }
          @ApiOperation(value="获取用户信息")
          @RequestMapping(value="description",method = RequestMethod.POST)
          public ReturnVo description(String username) {
              User user =  userRepository.findByUsername(username);
              return ReturnVo.ok(user.getDescription());
          }
      }
      
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值