轮子的使用
require firebase/php-jwt
一些常见的坑
签名的颁发者最好是个域名,最***看官方案例
生成的token会很长,建议存储token的字段用 text 类型
加密的类型要和解密的类型一样,默认是HS256加密
丢案例
namespace app\api\controller\v1;
use app\common\exception\ParamException;
use app\common\model\JwtToken;
use app\common\model\User;
use Firebase\JWT\JWT;
use think\Collection;
use think\exception\HttpResponseException;
use think\facade\Request;
use think\Response;
class Token
{
private $client_id;
private $secret_key;
private $token;
public function __construct($client_id = null,$secret_key = null)
{
$data = Request::param();
if($client_id != null || !empty($data['client_id']) )
{
$this->client_id = $client_id OR $this->client_id = $data['client_id'] ;
}else{
throw new ParamException(['msg'=>'client_id is nodefined']);
}
if($secret_key != null || !empty($data['secret_key']))
{
$this->secret_key = $secret_key OR $this->secret_key = $data['secret_key'];
}
if(!empty(Request::header('token')))
{
$this->token = Request::header('token');
}
}
/**
* 获取token
* @return array
*/
public function getToken($type = 'json',$force = false)
{
if(!isset($this->secret_key)){
throw new ParamException(['msg'=>'secret_key is nodefined']);
}
$obj = (new JwtToken())->get(['uid'=>$this->client_id,'key'=>$this->secret_key]);
if($obj)
{
$expA = $obj->getData('temp_token');
$expB = time() > $obj->getData('expire_time');
}else{
throw new ParamException(['msg'=>'client_id OR secret_key Exception']);
}
if(!$expA) {
$result = $this->TokenHandler('generate');
}else if($expB){
$result = $this->TokenHandler('update');
}else if($expA && !$expB){
if($force)
{
$result = $this->TokenHandler('update');
}else{
$result = ['temp_token'=>$expA, 'expire_time'=>$obj->getData('expire_time')];
}
}
switch($type)
{
case 'json':
$response = Response::create($result,'json');
throw new HttpResponseException($response);
break;
case 'array':
return $result;
break;
};
}
/**
* 签发token
* @return array
*/
private function issueToken()
{
$key = $this->secret_key;
$userData = (new User())->get(['id'=>$this->client_id]);
$nowTime = time();
$exp_time = $nowTime + 7200;
$jwt = [
'iss' => $_SERVER['HTTP_HOST'],
'iat' => $nowTime,
'nbf' => $nowTime + 10,
'exp' => $exp_time,
'data' => $userData->getData()
];
$token = (new JWT())->encode($jwt, $key);
$result = ['temp_token'=>$token, 'expire_time'=>$exp_time];
return $result;
}
/**
* 生成或更新token
* @return array
*/
private function TokenHandler($type)
{
$tokenInfo = $this->issueToken();
$map = [
'temp_token' => $tokenInfo['temp_token'],
'expire_time' => $tokenInfo['expire_time']
];
switch($type)
{
case 'generate':
$map['create_time'] = time();
break;
case 'update':
$map['update_time'] = time();
break;
};
$result = (new JwtToken())->update($map,['uid'=>$this->client_id]);
if($result)
{
return $tokenInfo;
}
}
/**
* 验证token
*/
public function checkToken()
{
try{
$res = $this->getTokenContent('array');
$TokenInID = $res['data']->id;
if($this->client_id == $TokenInID)
{
return true;
}else{
throw new ParamException(['msg'=>'Token and Client_id Exception']);
}
}catch(\Firebase\JWT\SignatureInvalidException $e){ //签名不正确
throw new ParamException(['msg'=>$e->getMessage()]);
}catch (\Firebase\JWT\BeforeValidException $e){ // 签名在某个时间点之后才能用
throw new ParamException(['msg'=>$e->getMessage()]);
}catch(\Firebase\JWT\ExpiredException $e) { // token过期
throw new ParamException(['msg'=>$e->getMessage()]);
}catch(\Exception $e) { //其他错误
throw new ParamException(['msg'=>$e->getMessage()]);
}
}
/**
* 解包token
* @param $token
* @param $key
* @return object
*/
private function decryptToken($token,$key)
{
JWT::$leeway = 60;
$result = (new JWT())->decode($token, $key, ['HS256']);
return $result;
}
/**
* 获取token的内容
*/
public function getTokenContent($type)
{
$key = $this->keyToClientID($this->client_id);
$result = $this->decryptToken($this->token,$key);
switch($type)
{
case 'json':
$res = Collection::make($result)->toArray();
$response = Response::create($res,'json');
throw new HttpResponseException($response);
break;
case 'array':
$res = Collection::make($result)->toArray();
return $res;
break;
}
}
/**
* 根据通信id返回秘钥
* @param $client_id
* @return mixed
* @throws ParamException
*/
private function keyToClientID($client_id)
{
$res = (new JwtToken())->get(['uid'=>$client_id]);
if($res)
{
return $res->getData('key');
}else{
throw new ParamException(['msg'=>'secret_key nodefiend']);
}
}
}
看效果