服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - PHP教程 - 基于PHP实现JWT登录鉴权的示例代码

基于PHP实现JWT登录鉴权的示例代码

2022-11-08 15:01PHP开源社区 PHP教程

JWT(JSON Web Token)是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准。本文将为大家介绍PHP如何实现JWT登录鉴权,需要的可以参考一下

一、什么是JWT

1、简介

JWT(JSON Web Token)是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准。

简单的说,JWT就是一种Token的编码算法,服务器端负责根据一个密码和算法生成Token,然后发给客户端,客户端只负责后面每次请求都在HTTP header里面带上这个Token,服务器负责验证这个Token是不是合法的,有没有过期等,并可以解析出subject和claim里面的数据。

2、JWT的组成

第一部分为头部(header),第二部分我们称其为载荷(payload),第三部分是签证(signature)。【中间用 . 分隔】

一个标准的JWT生成的token格式如下:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImp0aSI6IjRmMWcyM2ExMmFhMTEifQ.eyJpc3MiOiJodHRwOlwvXC9leGFtcGxlLmNvbSIsImF1ZCI6Imh0dHA6XC9cL2V4YW1wbGUub3JnIiwianRpIjoiNGYxZzIzYTEyYWExMSIsImlhdCI6MTY0MDE3MTA1MywibmJmIjoxNjQwMTcxMDU0LCJleHAiOjE2NDAxNzQ2NTMsInVpZCI6MjAsInVzZXJuYW1lIjoiTWFrZSJ9.bysUwNIyhqqEyL0JecSHdplSTfE6G6zuCsrAn6eyrQM

使用https://jwt.io/这个网站对JWT Token进行解析的结果如下

基于PHP实现JWT登录鉴权的示例代码

3、JWT验证流程和特点

验证流程:

① 在头部信息中声明加密算法和常量, 然后把header使用json转化为字符串

② 在载荷中声明用户信息,同时还有一些其他的内容;再次使用json 把载荷部分进行转化,转化为字符串

③ 使用在header中声明的加密算法和每个项目随机生成的secret来进行加密, 把第一步分字符串和第二部分的字符串进行加密, 生成新的字符串。词字符串是独一无二的。

④ 解密的时候,只要客户端带着JWT来发起请求,服务端就直接使用secret进行解密。

特点:

① 三部分组成,每一部分都进行字符串的转化

② 解密的时候没有使用数据库,仅仅使用的是secret进行解密

③ JWT的secret千万不能泄密!

④ 不依赖数据库,而是直接根据token取出保存的用户信息,以及对token可用性校验,校验方式更加简单便捷化,单点登录更为简单。

二、相关问题

  • JWT Token需要持久化在redis、Memcached中吗?

不应该这样做,无状态的jwt变成了有状态了,背离了JWT通过算法验证的初心。

  • 在退出登录时怎样实现JWT Token失效呢?

退出登录, 只要客户端端把Token丢弃就可以了,服务器端不需要废弃Token。

  • 怎样保持客户端长时间保持登录状态?

服务器端提供刷新Token的接口, 客户端负责按一定的逻辑刷新服务器Token。

三、PHP实现

1、引入依赖

?
1
composer require lcobucci/jwt 3.*

2、功能实现

  • 签发token, 设置签发人、接收人、唯一标识、签发时间、立即生效、过期时间、用户id、用户username、签名。其中,用户id、用户username是特意存储在token中的信息,也可以增加一些其他信息,这样在解析的时候就可以直接获取到这些信息,不能是敏感数据
  • 验证令牌验证这个Token是不是合法的,有没有过期等,并可以解析出subject和claim里面的数据,传递jwt token的方式为Authorization中的Bearer Token,如下

基于PHP实现JWT登录鉴权的示例代码

3、封装工具类如下

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
<?php
/**
 * Created by PhpStorm
 * @author sxd
 */
 
namespace App\Utils;
 
 
use Lcobucci\JWT\Configuration;
use Lcobucci\JWT\Parser;
use Lcobucci\JWT\Signer\Hmac\Sha256;
use Lcobucci\JWT\Signer\Key\InMemory;
use Lcobucci\JWT\Token\Plain;
use Lcobucci\JWT\Validation\Constraint\IdentifiedBy;
use Lcobucci\JWT\Validation\Constraint\IssuedBy;
use Lcobucci\JWT\Validation\Constraint\PermittedFor;
use Lcobucci\JWT\ValidationData;
 
class JwtUtil
{
    // jwt github: https://github.com/lcobucci/jwt     https://jwt.io/
    protected $issuer = "http://example.com";
    protected $audience = "http://example.org";
    protected $id = "4f1g23a12aa11";
    // key 是绝对不允许泄露的
    protected static $key = "8swQsm1Xb0TA0Jw5ASPwClKVZPoTyS7GvhtaW0MxzKEihs1BNpcS2q3FYMJ11111";
 
    /**
     * 签发令牌
     */
    public function getToken()
{
        $time = time();
        $config = self::getConfig();
        assert($config instanceof Configuration);
 
        // 签发token, 设置签发人、接收人、唯一标识、签发时间、立即生效、过期时间、用户id、用户username、签名
        $token = $config->builder()
            ->issuedBy($this->issuer) // Configures the issuer (iss claim)
            ->permittedFor($this->audience) // Configures the audience (aud claim)
            ->identifiedBy($this->id, true) // Configures the id (jti claim), replicating as a header item
            ->issuedAt($time) // Configures the time that the token was issue (iat claim)
            ->canOnlyBeUsedAfter($time + 1) // Configures the time that the token can be used (nbf claim)  签发x秒钟后生效
            ->expiresAt($time + 3600) // Configures the expiration time of the token (exp claim)
            ->withClaim('uid', 20) // Configures a new claim, called "uid"
            ->withClaim('username', "Make") // Configures a new claim, called "uid"
            ->getToken($config->signer(), $config->signingKey()); // Retrieves the generated token
        return $token->toString();
    }
 
    /**
     * 验证 jwt token 并返回其中的用户id
     * verify token
     */
    public function verifyToken_bak($token)
{
        try {
            $config = self::getConfig();
            assert($config instanceof Configuration);
 
            $token = $config->parser()->parse($token);
            assert($token instanceof Plain);
 
            //Lcobucci\JWT\Validation\Constraint\IdentifiedBy: 验证jwt id是否匹配
            //Lcobucci\JWT\Validation\Constraint\IssuedBy: 验证签发人参数是否匹配
            //Lcobucci\JWT\Validation\Constraint\PermittedFor: 验证受众人参数是否匹配
            //Lcobucci\JWT\Validation\Constraint\RelatedTo: 验证自定义cliam参数是否匹配
            //Lcobucci\JWT\Validation\Constraint\SignedWith: 验证令牌是否已使用预期的签名者和密钥签名
            //Lcobucci\JWT\Validation\Constraint\StrictValidAt: ::验证存在及其有效性的权利要求中的iat,nbf和exp(支持余地配置
            //Lcobucci\JWT\Validation\Constraint\LooseValidAt: 验证的权利要求iat,nbf和exp,当存在时(支持余地配置)
 
            //验证jwt id是否匹配
            $validate_jwt_id = new IdentifiedBy($this->id);
            //验证签发人url是否正确
            $validate_issued = new IssuedBy($this->issuer);
            //验证客户端url是否匹配
            $validate_aud = new PermittedFor($this->audience);
            $config->setValidationConstraints($validate_jwt_id, $validate_issued, $validate_aud);
 
            $constraints = $config->validationConstraints();
 
            if (!$config->validator()->validate($token, ...$constraints)) {
                die("token invalid!");
            }
        } catch (\Exception $e) {
            die("error:" . $e->getMessage());
        }
        $jwtInfo = $token->claims();  // 这是jwt token中存储的所有信息
        return $jwtInfo->get("uid");  // 获取uid
    }
 
    /**
     * 加密解密使用的配置
     * @return Configuration
     */
    public static function getConfig()
{
        $configuration = Configuration::forSymmetricSigner(
        // You may use any HMAC variations (256, 384, and 512)
            new Sha256(),
            // replace the value below with a key of your own!
            InMemory::base64Encoded(self::$key)
        // You may also override the JOSE encoder/decoder if needed by providing extra arguments here
        );
        return $configuration;
    }
 
    /**
     * 另一种验证方法,但是已经弃用
     * verify token
     */
    public function verifyToken($token)
{
        $token = (new Parser())->parse((string)$token);
        //验证token
        $data = new ValidationData();
        $data->setIssuer($this->issuer);//验证的签发人
        $data->setAudience($this->audience);//验证的接收人
        $data->setId($this->id);//验证token标识
 
        if (!$token->validate($data)) {
            //token验证失败
            die("token invalid!");
        }
        $jwtInfo = $token->claims();  // 这是jwt token中存储的所有信息
        return $jwtInfo->get("uid");  // 获取uid
    }
 
}

以上就是基于PHP实现JWT登录鉴权的示例代码的详细内容,更多关于PHP JWT登录鉴权的资料请关注服务器之家其它相关文章!

原文链接:https://mp.weixin.qq.com/s/RqGJMkCCeGtR1zjrALuVNw

延伸 · 阅读

精彩推荐