作用: 替代 session 的身份验证方案
运行过程:
image.pngtoken相对cookie, session 的优点 :
1. 不用将数据暴露给客户端(cookie)
2. 不需要存储大量信息, 而是存一个字符串, 减轻存储压力 ; 存放位置从服务器内存转到数据库, 避免因用户量增大时登录状态异常
3. 对于分布式服务器架构支持好, 避免了访问其他服务器登录无效(session)
流行的跨域认证解决方案: JWT
JWT相对传统token的优点:
- 不需要查询数据库, 解密判定用户状态速度更快
- 支持签名加密, 防止数据(head/payload)篡改
构成
header + payload + Signature
如何解决超有效期?如何判断离线?
JWT算法:
$code1= base64UrlEncode( header ) . "." . base64UrlEncode( payload )
code1))
code1 . "." . $signature
base64UrlEncode算法:
字符串进行一次base64Encode, 将所得新字符串的=清除, "+" 替换为"-", "/" 替换为 "_"
Base64UrlDecode算法:
...
JWT运行过程:
image.pngJWT 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);
网友评论