firuze / jwt
JSON Web Token (JWT) for webman 插件
Requires
- php: ^7.1||^8.0
- ext-json: *
- firebase/php-jwt: ^6.8
- workerman/webman-framework: ^1.2.1
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.6
- illuminate/database: ^8.83
- mockery/mockery: ^1.5
- phpstan/phpstan: ^1.4
- phpunit/phpunit: ^9.0
- topthink/think-orm: ^2.0
- vimeo/psalm: ^4.22
README
Json web token (JWT) 是一种基于网络应用环境之间声明传输的 JSON 开放标准(RFC 7519),应设计成紧凑且安全,特别适用于分布式站点单点登录(SSO)场景。
JWT 声明通常用于在身份提供者和服务提供者之间传递已认证的用户身份信息,以便从资源服务器获取资源,也可以增加其他业务逻辑所需声明的信息。令牌也可以直接用于认证或加密。
认证与授权过程
签名过程
- 用户使用用户名和密码向认证服务器请求认证。
- 认证服务器验证用户名和密码后,生成 JWT Token,该令牌的生成过程如下:
- 认证服务器还将生成一个密钥(密钥)
- 分别对 JWT 标题和 JWT 有效负载进行 Base64 编码。有效负载可能包括用户的抽象 ID 和过期时间。
- 对密钥进行签名以生成 JWT
HMAC-SHA256(SecretKey, Base64UrlEncode(JWT-Header)+'.'+Base64UrlEncode(JWT-Payload))
- 然后
base64(header).base64(payload).signature
将作为 JWT 令牌返回给客户端。 - 客户端使用 JWT 令牌向应用程序服务器发送相关请求。此 JWT 令牌类似于临时用户证书。
安装
composer require firuze/jwt
使用
令牌
use Firuze\Jwt\JwtToken; $user = [ 'id' => 2022, 'name' => 'Firuze', 'email' => 'Firuze@163.com' ]; $token = JwtToken::generateToken($user); var_dump(json_encode($token));
输出(json 格式)
{ "token_type": "Bearer", "expires_in": 36000, "access_token": "eyJ0eXAiOiJAUR-Gqtnk9LUPO8IDrLK7tjCwQZ7CI...", "refresh_token": "eyJ0eXAiOiJIEGkKprvcccccQvsTJaOyNy8yweZc..." }
响应参数
支持功能列表
- 获取当前
id
$id = Firuze\Jwt\JwtToken::getCurrentId();
- 获取所有字段
$email = Firuze\Jwt\JwtToken::getExtend();
- 获取自定义字段
$email = Firuze\Jwt\JwtToken::getExtendVal('email');
- 刷新令牌(通过获取新令牌来获取访问令牌)
$refreshToken = Firuze\Jwt\JwtToken::refreshToken();
- 令牌的有效剩余时间
$exp = Firuze\Jwt\JwtToken::getTokenExp();
- 单设备登录。默认为关闭,请修改配置文件
config/plugin/firuze/jwt
'is_single_device' => true,
单设备登录支持定义
client
字段,自定义客户端单点登录(默认为WEB
,网页),例如:MOBILE
、APP
、WEB
、ADMIN
、API
、OTHER
等。
$user = [ 'id' => 2022, 'name' => 'Firuze', 'client' => 'MOBILE', ]; $token = Firuze\Jwt\JwtToken::generateToken($user); var_dump(json_encode($token));
- 获取当前用户信息(模型)
$user = Firuze\Jwt\JwtToken::getUser();
此配置项 'User_model'
是一个匿名函数,默认返回空数组,可以根据自己的 ORM 自定义返回模型。
ThinkORM 配置
'user_model' => function($uid) { // Return a array return \think\facade\Db::table('resty_user') ->field('id,username,create_time') ->where('id',$uid) ->find(); }
LaravelORM 配置
'user_model' => function($uid) { // Return a object return \support\Db::table('resty_user') ->where('id', $uid) ->select('id','email','mobile','create_time') ->first(); }
- 令牌清理
$res = Firuze\Jwt\JwtToken::clear();
只有配置项
is_single_device
为true
时才生效。可选参数:MOBILE
、APP
、WEB
、ADMIN
、API
、OTHER
等。
- 自定义终端
Client
// Generate web token $user = [ 'id' => 2022, 'name' => 'Firuze', 'client' => JwtToken::TOKEN_CLIENT_WEB ]; $token = JwtToken::generateToken($user); // Generate mobile token $user = [ 'id' => 2022, 'name' => 'Firuze', 'client' => JwtToken::TOKEN_CLIENT_MOBILE ]; $token = JwtToken::generateToken($user);
默认为 WEB
端
- 自定义访问令牌和刷新令牌的过期时间
$extend = [ 'id' => 2024, 'access_exp' => 7200, // 2 Hour ]; $token = Firuze\Jwt\JwtToken::generateToken($extend);
签名算法
JWT 最常见的签名算法(JWA):HS256(HMAC-SHA256)
、RS256(RSA-SHA256)
以及 ES256(ECDSA-SHA256)
JWT 算法列表如下
+--------------+-------------------------------+--------------------+ | "alg" Param | Digital Signature or MAC | Implementation | | Value | Algorithm | Requirements | +--------------+-------------------------------+--------------------+ | HS256 | HMAC using SHA-256 | Required | | HS384 | HMAC using SHA-384 | Optional | | HS512 | HMAC using SHA-512 | Optional | | RS256 | RSASSA-PKCS1-v1_5 using | Recommended | | | SHA-256 | | | RS384 | RSASSA-PKCS1-v1_5 using | Optional | | | SHA-384 | | | RS512 | RSASSA-PKCS1-v1_5 using | Optional | | | SHA-512 | | | ES256 | ECDSA using P-256 and SHA-256 | Recommended+ | | ES384 | ECDSA using P-384 and SHA-384 | Optional | | ES512 | ECDSA using P-521 and SHA-512 | Optional | | PS256 | RSASSA-PSS using SHA-256 and | Optional | | | MGF1 with SHA-256 | | | PS384 | RSASSA-PSS using SHA-384 and | Optional | | | MGF1 with SHA-384 | | | PS512 | RSASSA-PSS using SHA-512 and | Optional | | | MGF1 with SHA-512 | | | none | No digital signature or MAC | Optional | | | performed | | +--------------+-------------------------------+--------------------+ The use of "+" in the Implementation Requirements column indicates that the requirement strength is likely to be increased in a future version of the specification.
您可以看到只有 RS256 和 ES256 被标记为推荐。
对称加密算法
插件安装使用
HS256
对称加密算法。
HS256 使用相同的 「secret_key」
进行签名和验证。一旦 secret_key
不安全,则没有任何安全性。因此 HS256 仅适用于集中式认证,签名和验证必须由受信任方执行。
非对称加密算法
RS256 系列使用 RSA 私钥进行签名,并使用 RSA 公钥进行验证。
即使公钥没有作用,只要私钥安全,它就没有影响。RS256可以将验证委托给其他应用,只要提供公钥。
以下为RS系列算法的命令,仅供参考
RS512
ssh-keygen -t rsa -b 4096 -E SHA512 -m PEM -P "" -f RS512.key openssl rsa -in RS512.key -pubout -outform PEM -out RS512.key.pub
RS512
ssh-keygen -t rsa -b 4096 -E SHA354 -m PEM -P "" -f RS384.key openssl rsa -in RS384.key -pubout -outform PEM -out RS384.key.pub
RS256
ssh-keygen -t rsa -b 4096 -E SHA256 -m PEM -P "" -f RS256.key openssl rsa -in RS256.key -pubout -outform PEM -out RS256.key.pub
🚀 视频地址
不理解的学生可以通过视频来理解,会有详细的解释
- 如何使用JWT认证插件:https://www.bilibili.com/video/BV1HS4y1F7Jx
- 如何使用JWT认证插件(算法):https://www.bilibili.com/video/BV14L4y1g7sY
安全
https://www.w3cschool.cn/fastapi/fastapi-cmia3lcw.html
概念
处理诸如安全、身份认证和授权等问题有许多方法。这通常是一个复杂且“困难”的话题。在许多框架和系统中,处理安全和身份认证可能需要大量的精力和代码(在许多情况下,可能占所有代码的50%以上)。
JWT可以帮助您轻松快速地处理安全,无需学习所有安全规范。
场景
假设你有一个后端API在某个域中。你还有一个在另一个域或相同域中的前端(或移动应用)。你希望前端能够使用用户名和密码,而后端进行身份验证。我们可以使用JWT通过OAUTH2来实现。
认证过程
- 用户在前端输入
用户名
和密码
,然后点击Enter。 - 前端(在用户的浏览器中运行)将
用户名
和密码
发送到我们的API特定的URL(声明tokenUrl="token"
)。 - API检查用户名和密码,并响应“token”(我们还没有实现这些)。这个“token”只是一个包含一些内容的字符串。我们以后可以用它来验证这个用户。通常,令牌会在一段时间后过期。因此,用户以后将需要再次登录。如果令牌被盗,风险很小。它不像永久有效的密钥(在大多数情况下)。前端临时存储在某个地方。
- 用户点击前端跳转到前端web应用的另一部分。
- 前端需要从API获取更多数据。但它需要验证特定的端点。因此,为了使用我们的API进行认证,它将发送包含
Authorization
值Bearer
的token头。如果token包含foobar
,则Authorization
头的内 容将是:Bearer foobar
。注意:中间有一个空格
。