您现在的位置是:主页 > 技术领域 > PHP > PHP

JWT

追风 2021-11-15 PHP 人已围观

简介本文主要介绍jwt的相关知识

JWT方式的Token认证
 
 
1.JWT 的特点和验证流程:
              JWT 是 Json Web Tokens 的缩写,与传统 Web 的 Cookies 或者 Session 方式的认证不同的是,JWT 是无状态的,服务器上不需要对 token 进行存储,也不需要和客户端保持连接。
              服务器上会保存一个全局 JWT_SECRET ,用于生成 token 和验证 token。在用户登录成功后,服务器从数据库获取用户的相关信息,计算出 token 到期时间,生成头部和负载并编码,再将前面的内容使用 JWT_SECRET 进行加密,生成签名,最后将3个部分合并返回给客户端。
              客户端访问需要认证的客户端时,在 Http 请求头部加上 Authrization 字段,内容为 Bearer 加 token。服务器收到请求后,利用 JWT_SECRET 验证 token 是否合法,从负载中提取到期时间确认 token 是否过期,再从 token 提取用户信息,与数据库进行对比。如果这些都通过的话就可以进行后续操作了。
            
Token Auth 机制优势 
1. 支持跨域
2. 无状态,JWT 就是将会话状态存在了客户端(cookie), 服务器端需要的时候自然会解析验证. 也没有多服务器间的同步麻烦.
3. 更适用于移动应用(当客户端是原生应用时,Cookie支持不佳)
4. 安全性更强,可以防范常见的CSRF(跨站请求伪造)
5. 有完善的业界标准(后文将提到的JWT)
 
2.组成:
          JWT 的 token 分3个部分   [header.payload.signature]
              头部 ,表明这是一个JWT,并指明加密方式,
                  怎样生成A?(头部)
           header格式为:
 
{
    "typ": "JWT",
    "alg": "HS256"
}
 它就是一个json串,两个字段是必须的,不能多也不能少。alg字段指定了生成C的算法,默认值 是HS256。将header用base64加密,得到A 。通常,JWT库中,可以把A部分固定写死,用户最多指定一个alg的取值
      
             负载
                   其中可以包含 账户名、ID、邮箱等用户信息,同时也包含了token到期时间,以 Unix 时间戳的方式记录,头部和负载都会进行 base64 编码,最后一部分是签名,用来验证负载的信息是否正确。
       怎样生成B?(负载)
                   根据JWT claim set[用base64]加密得到的。claim set是一个json数据,是表明用户身份的数据,可自行指定字段很灵活,也有固定字段表示特定含义(但不一定要包含特定字段,只是推荐)。
                  JWT遵循RFC7519标准,里面提到claim set的json数据中,自定义字段的key是一个string,value是一个json数据。因此随意编写吧,很灵活。
           
$token=array(
    "user_id" => 123456, #用户id,表明用户
    "iat" => 1356999524, #token发布时间
    "exp" => 1556999524, #token过期时间
);
 
      签名
      怎样计算C?(签名)
           将A.B使用HS256加密(其实是用header中指定的算法),当然加密过程中还需要密钥(自行指定的一个字符串)。加密得到C,学名signature,其实就是一个字符串。作用类似于CRC校验,保证加密没有问题。
     
 
3.使用 
               可以放到HTTP请求的请求头中,通常是Authorization字段。 
 
 4.token应用流程
              1.初次登录:用户初次登录,输入用户名密码
              2.密码验证:服务器从数据库取出用户名和密码进行验证
              3.生成JWT:服务器端验证通过,根据从数据库返回的信息,以及预设规则,生成JWT
              4.返还JWT:服务器的HTTP RESPONSE中将JWT返还
              5.带JWT的请求:以后客户端发起请求,HTTP REQUEST HEADER中的Authorizatio字段都要有值,为JWT 
 
5.梳理方法 
    $key = 'D6eX+Y7#Jk';密钥随便写
 
encode
public static function encode(array $payload, string $key, string $alg = 'SHA256')    {
        $key = md5($key);
        $jwt = base64_encode(json_encode(['typ' => 'JWT''alg' => $alg])) .'.' . base64_encode(json_encode($payload));
        return $jwt . '.' . self::signature($jwt$key$alg);
}
 
sign
public static function signature(string $input, string $key, string $alg) {
        return hash_hmac($alg$input$key);
}
 
decode
public static function decode(string $jwt, string $key)  {
        $tokens = explode('.'$jwt);
        $key    = md5($key);
 
 
        if (count($tokens) != 3)
            return false;
 
 
        list($header64$payload64$sign) = $tokens;
 
 
        $header = json_decode(base64_decode($header64), JSON_OBJECT_AS_ARRAY);
        if (empty($header['alg']))
            return false;
 
 
        if (self::signature($header64 . '.' . $payload64$key$header['alg']) !== $sign)
            return false;
 
 
        $payload = json_decode(base64_decode($payload64), JSON_OBJECT_AS_ARRAY);
 
 
        $time = $_SERVER['REQUEST_TIME'];
        if (isset($payload['iat']) && $payload['iat'] > $time)
            return false;
 
 
        if (isset($payload['exp']) && $payload['exp'] < $time)
            return false;
        return $payload;
  }
 
 
 

相关文章

文章评论