🎈 Token Authentication Process
- As the most popular cross-domain authentication solution,
JWT(JSON Web Token)
is deeply loved by developers. The main process is as follows: - The client sends an account and password to request a login
- The server receives the request to verify whether the account password is passed
- After the verification is successful, the server will generate a unique
token
and return it to the client - The client receives
token
and stores it in cookie
or localStroge
- After each time the client sends a request to the server, it will pass
cookie
or header
to carry the token
- The server verifies the validity of
token
, and returns the response data after passing

🎈 Token Authentication Advantages
- Support cross-domain access:
Cookie
is not allowed to cross-domain access, this point Token
the mechanism does not exist, the premise is that the transmitted user authentication information passes HTTP
header transfer - Stateless:
Token
mechanism does not need to store session
information on the server, because Token
itself contains all the information of logged in users, only needs to be stored on the client cookie
or local media storage status information - Wider applicability: As long as it is a client that supports the
http
protocol, it can use token
authentication. - 无需考虑CSRF:
cookie
, token
认证方式不会CSRF
, CSRF
defense
🎈 JWT structure
- A
JWT
is actually a string consisting of three parts: 头部
, 载荷
and 签名
. The middle is separated into three parts by a dot .
. Note JWT
there is no line break inside.

- 🎨header /header
-
header
组成: token
的类型JWT
名称: HMAC
、 SHA256
、 RSA
{
"alg": "HS256",
"typ": "JWT"
}
- 🎨Payload
-
Payload
part is also a JSON
object, which is used to store the actual data that needs to be passed. JWT
Specify seven default fields for selection. - In addition to the default fields, you can add any fields you want. Generally, after a user logs in successfully, the user information is stored here
iss:发行人
exp:到期时间
sub:主题
aud:用户
nbf:在此之前不可用
iat:发布时间
jti:JWT ID用于标识该JWT
{
"iss": "xxxxxxx",
"sub": "xxxxxxx",
"aud": "xxxxxxx",
"user": [
'username': '极客飞兔',
'gender': 1,
'nickname': '飞兔小哥'
]
}
- 🎨Signature
- The signature part is the data signature for the above header and payload data.
- In order to ensure that the data is not tampered with, you need to specify a key, and this key is generally only known to you and stored on the server
- The code to generate the signature is generally as follows:
// 其中secret 是密钥
String signature = HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
🎈 Basic use of JWT
- The client receives the
JWT
returned by the server, which can be stored in Cookie
, or in localStorage
- Then every time the client communicates with the server, it must bring this
JWT
- Save ---
JWT
in Cookie
and send the request, so it cannot 跨域
- A better practice is to put it in the
HTTP
request header information Authorization
field
fetch('license/login', {
headers: {
'Authorization': 'X-TOKEN' + token
}
})
🎈 Actual combat: use JWT login authentication
- Here use
ThinkPHP6
integration JWT
login authentication for actual combat simulation - 🎨 Install JWT extension
composer require firebase/php-jwt
- 🎨 Encapsulate the generated JWT and decryption method
<?php
/**
* Desc: JWT认证
* Author: autofelix
* Time: 2022/07/04
*/
namespace app\services;
use app\Helper;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
class JwtService
{
protected $salt;
public function __construct()
{
//从配置信息这种或取唯一字符串,你可以随便写比如md5('token')
$this->salt = config('jwt.salt') || "autofelix";
}
// jwt生成
public function generateToken($user)
{
$data = array(
"iss" => 'autofelix', //签发者 可以为空
"aud" => 'autofelix', //面象的用户,可以为空
"iat" => Helper::getTimestamp(), //签发时间
"nbf" => Helper::getTimestamp(), //立马生效
"exp" => Helper::getTimestamp() + 7200, //token 过期时间 两小时
"user" => [ // 记录用户信息
'id' => $user->id,
'username' => $user->username,
'truename' => $user->truename,
'phone' => $user->phone,
'email' => $user->email,
'role_id' => $user->role_id
]
);
$jwt = JWT::encode($data, md5($this->salt), 'HS256');
return $jwt;
}
// jwt解密
public function chekToken($token)
{
JWT::$leeway = 60; //当前时间减去60,把时间留点余地
$decoded = JWT::decode($token, new Key(md5($this->salt), 'HS256'));
return $decoded;
}
}
- 🎨After the user logs in, generate a JWT ID
<?php
declare (strict_types=1);
namespace app\controller;
use think\Request;
use app\ResponseCode;
use app\Helper;
use app\model\User as UserModel;
use app\services\JwtService;
class License
{
public function login(Request $request)
{
$data = $request->only(['username', 'password', 'code']);
// ....进行验证的相关逻辑...
$user = UserModel::where('username', $data['username'])->find();
// 验证通过生成 JWT, 返回给前端保存
$token = (new JwtService())->generateToken($user);
return json([
'code' => ResponseCode::SUCCESS,
'message' => '登录成功',
'data' => [
'token' => $token
]
]);
}
}
- 🎨 Middleware to verify if the user is logged in
- Register the middleware at
middleware.php
<?php
// 全局中间件定义文件
return [
// ...其他中间件
// JWT验证
\app\middleware\Auth::class
];
- After registering the middleware, improve the verification logic in the permission verification middleware
<?php
declare (strict_types=1);
namespace app\middleware;
use app\ResponseCode;
use app\services\JwtService;
class Auth
{
private $router_white_list = ['login'];
public function handle($request, \Closure $next)
{
if (!in_array($request->pathinfo(), $this->router_white_list)) {
$token = $request->header('token');
try {
// jwt 验证
$jwt = (new JwtService())->chekToken($token);
} catch (\Throwable $e) {
return json([
'code' => ResponseCode::ERROR,
'msg' => 'Token验证失败'
]);
}
$request->user = $jwt->user;
}
return $next($request);
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。