PHP JWT验证的实践
介绍
JWT
JSON Web Tokens
JWT 格式 header.payload.signature
header
{
"typ":"JWT",
"alg":"SHA256"
}
payload
待补充
示例
<?php
/**
* api接口基类控制器
* @authors vilay
*/
namespace api\controllers;
use Yii;
use yii\web\Controller;
class ApiController extends Controller
{
public $data;//存储数据
public $jwt;//jwt字符串
/**
* 允许授权的域名
* @var [type]
*/
public $aud = [
'app id'=>'app name',
];
private $secret_key = 'app secret';
public $enableCsrfValidation = false;
public function init()
{
if (!Yii::$app->request->headers->has('Authorization')) {
return false;
}
$headers = Yii::$app->request->headers->get('Authorization');
$this->data = json_decode(Yii::$app->request->post('data'),true);
}
/**
* 响应json数据
* @param array $data 数组
* @param string $msg 消息提示
* @param int|integer $code 状态码 0 表示数据错误或者请求非法,200 请求成功
* @return [type] [description]
* 基本数据返回
* {
"code": 200,
"data": {
"token": "token"
},
"msg": ""
}
列表数据返回
{
"code":200,
'data': {
'lists':{
}, //列表数据集
'total':50,//总纪录数
'page':2, //下一页页码,客户端请求需要返回
'next':1,//是否有下一页
},
'msg':''
}
*/
public function jsonData(array $data, string $msg='', int $code=200):array
{
$response = [
'code' => $code,
'data' => $data,
'msg' => $msg
];
return $response;
}
/**
* 客户端请求token
* @return [type] [description]
*/
public function actionGetToken()
{
//验证合法请求id
if (!array_key_exists($this->data['aud'], $this->aud)) {
return false;
}
//验证合法请求来源域名,测试阶段注释
// $referer_url = Yii::$app->request->referrer;
// if (false === strpos($referer_url, $this->aud[$this->data['aud']])) {
// return false;
// }
$data = [
'aud' => $this->aud[$this->data['aud']],
'jti' => $this->data['aud']
];
$token = $this->encode($data);
Yii::$app->response->format = 'json';
return $this->jsonData(['token'=>$token]);
}
/**
* 生成JWT数据
* @param array $params [description]
* $params = [
* 'aud' => 'receive',//接收方
* 'jti' => 'app id',//客户端id
* ]
* @return [type] header.payload.signature
*/
private function encode(array $params):string
{
$secret_key = md5($this->secret_key);
$alg = 'SHA256';
$header = [
'typ' => 'JWT',
'alg' => $alg
];
$now = time();
$payload = [
'iss' => 'vilay',
'iat' => $now, //token创建世界
'exp' => $now + 3600*8,//token过期时间
'aud' => $params['aud'],
'jti' => $params['jti']
];
$jwt = $this->base64JsonEncode($header).'.'.$this->base64JsonEncode($payload);
return $jwt.'.'.$this->signature($jwt, $secret_key, $alg);
}
/**
* base64,json编码
* @param [type] $data [description]
* @return [type] [description]
*/
private function base64JsonEncode($data)
{
return base64_encode(json_encode($data));
}
/**
* base64,json解码
* @param [type] $data [description]
* @return [type] [description]
*/
private function base64JsonDecode($data)
{
return json_decode(base64_decode($data),true);
}
private function decode(string $jwt)
{
$secret_key = md5($this->secret_key);
$tokens = explode('.',$jwt);
if (count($tokens) != 3) {
return false;
}
list($header, $payload, $signature) = $tokens;
$headers = $this->base64JsonDecode($header);
if (empty($headers['alg']) || empty($headers['typ'])) {
return false;
}
if ($signature != $this->signature($header.'.'.$payload, $secret_key, $headers['alg'])) {
return false;
}
$payload = $this->base64JsonDecode($payload);
$now = time();
if (isset($payload['iat']) && $payload['iat'] > $now) {
return false;
}
if (isset($payload['exp']) && $payload['exp'] < $now) {
return false;
}
return $payload;
}
/**
* 签名字符串
* @return [type] [description]
*/
private function signature(string $jwt, string $secret_key, string $alg='SHA256'):string
{
return hash_hmac($alg, $jwt, $secret_key);
}
}
}