token身份验证机制

2020-05-07  本文已影响0人  X1_blog

作用: 替代 session 的身份验证方案

运行过程:

image.png

token相对cookie, session 的优点 :

1. 不用将数据暴露给客户端(cookie)

2. 不需要存储大量信息, 而是存一个字符串, 减轻存储压力 ; 存放位置从服务器内存转到数据库, 避免因用户量增大时登录状态异常
3. 对于分布式服务器架构支持好, 避免了访问其他服务器登录无效(session)

流行的跨域认证解决方案: JWT

JWT相对传统token的优点:

  1. 不需要查询数据库, 解密判定用户状态速度更快
  2. 支持签名加密, 防止数据(head/payload)篡改

构成

header + payload + Signature

如何解决超有效期?如何判断离线?

JWT算法:

$code1= base64UrlEncode( header ) . "." . base64UrlEncode( payload )

signature = base64UrlEncode(alg_type(code1))

jwt =code1 . "." . $signature

base64UrlEncode算法:

字符串进行一次base64Encode, 将所得新字符串的=清除, "+" 替换为"-", "/" 替换为 "_"

Base64UrlDecode算法:

...

JWT运行过程:

image.png

JWT token demo https://www.jb51.net/article/146790.htm

/*jwt加密测试*/
date_default_timezone_set('Asia/Shanghai');
class jwt{
    public $jwtcode;
    private $alg_array = [
        "HS256" => "sha256"
    ], 
    $key = "secret";

    function __construct($header,$payload){
        $this->header = $header;
        $this->payload = $payload;
    }
    
    function getJwtcode($alg="HS256"){
         $str = $this->base64UrlEncode($this->header) . "." . $this->base64UrlEncode($this->payload) ;
         $this->jwtcode = $str.".". $this->get_signature($str,$alg);
         return $this->jwtcode  ;
    }

    function base64UrlEncode($mixed)
    {
        if(gettype($mixed)!=="string")$mixed = json_encode($mixed,JSON_UNESCAPED_UNICODE);
        $str = base64_encode($mixed) ;
        $str = str_replace("=","",$str);
        $str = str_replace("+","-",$str);
        return $str = str_replace("/","_",$str);
    }


     private function base64UrlDecode(string $input)
      {
        $remainder = strlen($input) % 4;
        if ($remainder) {
          $addlen = 4 - $remainder;
          $input .= str_repeat('=', $addlen);
        }
        return base64_decode(strtr($input, '-_', '+/'));
      }
     

    function test(){
        $code ="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.XbPfbIHMI6arZ3Y922BhjWgQzWXcXNrz0ogtVhfEd2o";   // 覆盖官网生成的jwt
        echo ( $this->jwtcode === $code )?  "true" :  "false" ;
    }

    function get_signature($str,$alg){
        return $this->base64UrlEncode(hash_hmac($this->alg_array[$alg],$str, $this->key,true));
    }

    

    function validateJwtcode($str){
        $array = explode(".", $str);
        $signature = $array[2];
        $header = json_decode($this->base64UrlDecode($array[0]),JSON_UNESCAPED_UNICODE);
        $payload = json_decode($this->base64UrlDecode($array[1]),JSON_UNESCAPED_UNICODE);

        $this->header = $header;
        $this->payload = $payload;
        $alg = $header['alg'];

        $new_signature = $this->get_signature($array[0].'.'.$array[1], $alg);

        if($new_signature!==$signature){
            echo "数据篡改";
            return;
        }

        echo ($payload['exp'] - time() <=0) ? "超时过期" : "校验成功" ;

    }
}
$header = [
  "alg"=> "HS256",
  "typ"=> "JWT"
];
$payload = [
  "sub"=> "1234567890",
  "name" => "John Doe",
  "exp" => strtotime('2020-04-01 01:29:00') ,
];
$jwt = new jwt($header,$payload) ;
$jwtCode = $jwt->getJwtcode();      // 获取jwt
echo $jwtCode ."\n" ;
$jwt->validateJwtcode($jwtCode);    // 验证jwt可用, 验证身份时效

MD5 token demo

/*简单实现多种加密的token
$payload : exp(过期时间) + alg(加密算法) + 其他信息
$token = base64($payload) + "." + alg(base64($payload),$tokenKey)
*/
date_default_timezone_set('Asia/Shanghai');
class myToken{
    public $tokenCode = "";
    private $_alg_list = [
        "A" => "md5",
        "B" => "sha256",
    ];
    private $_tokenKey = "key" ;
    function base64encodeArray($array){
        $str = json_encode($array,JSON_UNESCAPED_UNICODE);
        return base64_encode($str);
    }

    function base64decodeArray($array){

    }

    function validateToken($str){
        $str_array = explode(".",$str);
        $payloadStr = $str_array[0];
        $signature = $str_array[1];
        $payloadStr = base64_decode($payloadStr);
        $payload = json_decode($payloadStr,JSON_UNESCAPED_UNICODE);
        $alg = $payload['alg'];

        $newSignature = $this->signatureEncode($str_array[0],$alg);
        if($signature !== $newSignature) echo "数据篡改" ;
        $exp = $payload['exp'];
        echo ($exp - strtotime("now") <=0 )? "超过有效期" : "token有效" ;
        
    }

    private function signatureEncode($str,$alg){
        $alg = $this->_alg_list[$alg];
        if($alg==="md5"){
            return md5($str.$this->_tokenKey);
        }
        if($alg==="sha256"){
            return hash_hmac("sha256",$str,$this->_tokenKey,$this->_tokenKey);
        }

    }

    public function get_tokenCode($payload){
        $alg = $payload['alg'];
        $base64Payload = $this->base64encodeArray($payload);
        $signature = $this->signatureEncode($base64Payload,$alg);
        return  $base64Payload . '.' . $signature ;
    }
    
}

$payload = [
    "alg" => "A" ,
    "sub"=> "1234567890",
    "name" => "John Doe",
    "exp" => strtotime('2020-04-02 15:34:00') ,
];
$token = new myToken();
$tokenCode = $token->get_tokenCode($payload);
$token->validateToken($tokenCode);
上一篇下一篇

猜你喜欢

热点阅读