1、composer 引入 jwt 组件
composer require firebase/php-jwt
2、编写代码(根据实际需要修改)
<?php
declare(strict_types = 1);
namespace app\controllers;
use app\common\Helper;
use Firebase\JWT\JWT;
use yii\base\Controller;
class TestController extends Controller
{
/**
* 登录
*
* @throws \Exception
*/
public function actionLogin()
{
// 验证验证码、用户名及密码
if (false) {
return Helper::msg(0, '登录失败,验证码、用户名或密码错误');
} else {
// 如果验证通过,假设从数据库中获取到的用户信息
$userInfo = [
'user_id' => 10000,
'user_name' => 'haveyb',
'is_admin' => 1,
'menus' => [1, 2, 6, 13],
];
// 生成jwt,以供后续请求时,后端服务器身份校验
$token = $this->getJwt($userInfo);
// 返回给前端的数据,以供前端本次请求的数据显示
$data = [
'user_id' => $userInfo['user_id'],
'user_name' => 'haveyb',
'menus' => $userInfo['menus'],
'token' => $token
];
return Helper::msg(1, 'success', $data);
}
}
/**
* 验证用户是否登录,如果登录,返回用户id等信息,否则返回false
*/
public function actionCheck()
{
// 假设客户端请求的token(正常流程应该是放在前端请求过来的header头中或者cookie中)
$requestToken = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczpcL1wvd3d3LmhhdmV5Yi5jb20iLCJjcmVhdGVfdGltZSI6MTU4NjMzMzAwMSwidXNlcl9pZCI6MTAwMDAsImlzX2FkbWluIjoxfQ.VrGWf6nfhy8g5f-MufZK7J_OnOkUKiVHp4p9E9JavQw';
// jwt 加解密密钥
$secret = $this->getJwtSecret();
// jwt 加解密方式
$alg = $this->getJwtAlg();
// 验证token是否有效
try {
$check = (array)JWT::decode($requestToken, $secret, [$alg]);
} catch (\Exception $e) {
return Helper::msg(0, '用户登录信息错误');
}
// 验证 jwt 有效期(可以有,可以没有,建议添加上)
if (time() - $check['create_time'] > 86400) {
return Helper::msg(0, '用户登录信息错误');
}
// 到数据库中查询用户id等信息,返回给调用的方法
return Helper::msg(1, 'success', $check);
}
/**
* 获取json web token
*
* @param $userInfo
* @return string
*/
private function getJwt($userInfo)
{
$secret = $this->getJwtSecret();
$alg = $this->getJwtAlg();
$currentTime = time();
$returnData = [
'iss' => 'https://www.haveyb.com',
'create_time' => $currentTime,
'user_id' => $userInfo['user_id'],
'is_admin' => $userInfo['is_admin'],
];
return JWT::encode($returnData, $secret, $alg);
}
/**
* 返回jwt密钥
*
* @return string
*/
private function getJwtSecret()
{
return 'BQXSD0PxCFPN/3xa06/94PWm++0ZKOHw83kP0=';
}
/**
* 返回jwt加解密方式
*
* @return string
*/
private function getJwtAlg()
{
return 'HS256';
}
}
3、校验结果:
访问 login 方法
访问check方法
说明:check 方法实际使用中应该由具体的方法调用,为的是校验身份以及获取用户id等信息。
4、安全上的防范
由于 jwt 一旦被其他人获取了,就可以伪造用户的身份进行操作,因此再安全上一定要注意。
(1)使用 https 协议
在http超文本传输协议加入SSL层,它在网络间通信是加密的,所以需要加密证书
(2)保证服务端用于生成token的签名不泄露,并比较晦涩难懂
(3)加入token 过期时间的校验
这样,即使其他人拿到token,没过多少时间,就过期了
(4)加入 token ip的校验,一旦用户ip发生变化,则要求用户重新登录
和加入过期时间类似,只要在生成token时,加入user_ip字段,后面客户端请求时,再校验下 user_ip