Lumen中JWT token 生成过程理解,分析一下源码

1 篇文章 0 订阅

我们的lumen项目中使用到了jwt,网上资料也有很多对jwt的分析,以及jwt拓展使用的

这里记录一下jwt的token生成,以及流程,了解token的来源。

项目中的login接口中使用登录者信息调用attempt接口获取$token 追根溯源从这里开始

$credentials = ['username' =>'123', 'password' => '123456';
$token = Auth::guard('user')->attempt($credentials);

Auth::guard('user')返回了一个看守器实例。jwt拓展详解

    public static function attempt($credentials = array(), $login = true)
    {
        return \Tymon\JWTAuth\JWTGuard::attempt($credentials, $login);
    }

代码追踪找到attempt实现的是JWTGuard类下的attempt接口:对用户身份进行验证并返回令牌 验证通过调用login方法登录并返回令牌

    public function attempt(array $credentials = [], $login = true)
    {
        $this->lastAttempted = $user = $this->provider->retrieveByCredentials($credentials);

        if ($this->hasValidCredentials($user, $credentials)) {
            return $login ? $this->login($user) : true;
        }

        return false;
    }

1.校验用户

$this->provider 就是 auth.php 配置文件的providers配置项

/*
    |--------------------------------------------------------------------------
    | 提供器配置
    |--------------------------------------------------------------------------
    |
    | Supported: "database", "eloquent"
    | 提供器定义怎么检索用户
    |
    */

    'providers' => [
        'admins' => [
            'driver' => 'eloquent',
            //'table'=>'t_platform_admin',
            'model' => App\Http\Models\Auth\Admin::class,
        ],
        'users' => [
            'driver' => 'eloquent',
            //'table'=>'t_admin',
            'model' => App\Http\Models\Auth\User::class,
        ],
    ],

eloquent 就是 EloquentUserProvider类,在这里我们找到了attempt调用的retrieveByCredentials方法.根据最开始给attempt方法的登录用户信息,去数据库中查找匹配

/**
     * Retrieve a user by the given credentials.
     *
     * @param  array  $credentials
     * @return \Illuminate\Contracts\Auth\Authenticatable|null
     */
    public function retrieveByCredentials(array $credentials)
    {
        if (empty($credentials) ||
           (count($credentials) === 1 &&
            array_key_exists('password', $credentials))) {
            return;
        }

        // First we will add each credential element to the query as a where clause.
        // Then we can execute the query and, if we found a user, return it in a
        // Eloquent User "model" that will be utilized by the Guard instances.
        $query = $this->createModel()->newQuery();

        foreach ($credentials as $key => $value) {
            if (! Str::contains($key, 'password')) {
                $query->where($key, $value);
            }
        }

        return $query->first();
    }

接下来就是用户信息的校验了,具体实现同样在 EloquentUserProvider

/**
     * Validate a user against the given credentials.
     *
     * @param  \Illuminate\Contracts\Auth\Authenticatable  $user
     * @param  array  $credentials
     * @return bool
     */
    public function validateCredentials(UserContract $user, array $credentials)
    {
        $plain = $credentials['password'];

        return $this->hasher->check($plain, $user->getAuthPassword());
    }

$this->hasher->checkIlluminate\Hashing\BcryptHasher

    /**
     * Check the given plain value against a hash.
     *
     * @param  string  $value
     * @param  string  $hashedValue
     * @param  array   $options
     * @return bool
     */
    public function check($value, $hashedValue, array $options = [])
    {
        if (strlen($hashedValue) === 0) {
            return false;
        }

        return password_verify($value, $hashedValue);
    }

至此完成用户信息校验, attempt进入 $this->login($user)方法.

2.生成token

    /**
     * Create a token for a user.
     *
     * @param  \Tymon\JWTAuth\Contracts\JWTSubject  $user
     *
     * @return string
     */
    public function login(JWTSubject $user)
    {
        $token = $this->jwt->fromUser($user);
        $this->setToken($token)->setUser($user);

        return $token;
    }

$this->jwt->fromUser($user);Tymon\JWTAuth\JWT

    public function fromUser(JWTSubject $user)
    {
        return $this->fromSubject($user);
    }
    public function fromSubject(JWTSubject $subject)
    {
        $payload = $this->makePayload($subject);//生成载荷

        return $this->manager->encode($payload)->get();
    }
生成载荷Payload
    public function makePayload(JWTSubject $subject)
    {
        //生成载荷进入factory类
        return $this->factory()->customClaims($this->getClaimsArray($subject))->make();
    }

Tymon\JWTAuth\Factory

    public function customClaims(array $customClaims)
    {
        $this->customClaims = $customClaims;

        return $this;
    }
    public function make($resetClaims = false)
    {
        $payload = $this->withClaims($this->buildClaimsCollection());

        if ($resetClaims) {
            $this->emptyClaims();
        }

        return $payload;
    }
    
    public function buildClaimsCollection()
    {
        return $this->buildClaims()->resolveClaims();
    }
    
    protected function buildClaims()
    {
        // remove the exp claim if it exists and the ttl is null
        if ($this->claimFactory->getTTL() === null && $key = array_search('exp', $this->defaultClaims)) {
            unset($this->defaultClaims[$key]);
        }

        // add the default claims
        foreach ($this->defaultClaims as $claim) {
            $this->addClaim($claim, $this->claimFactory->make($claim));
        }

        // add custom claims on top, allowing them to overwrite defaults
        return $this->addClaims($this->getCustomClaims());
    }
    
    protected function resolveClaims()
    {
        return $this->claims->map(function ($value, $name) {
            return $value instanceof Claim ? $value : $this->claimFactory->get($name, $value);
        });
    }
    
    public function map(callable $callback)
    {
        $keys = array_keys($this->items);

        $items = array_map($callback, $this->items, $keys);

        return new static(array_combine($keys, $items));
    }

make() 函数返回 $payload token中载荷

生成签名

payload之后,是signer的生成, 实例调用Tymon\JWTAuth\Providers\JWT\Namshi类的encode方法

$this->manager->encode($payload)->get();
    public function encode(array $payload)
    {
        try {
            $this->jws->setPayload($payload)->sign($this->getSigningKey(), $this->getPassphrase());

            return (string) $this->jws->getTokenString();
        } catch (Exception $e) {
            throw new JWTException('Could not create token: '.$e->getMessage(), $e->getCode(), $e);
        }
    }

encode方法实现 Namshi\JOSE\JWS

    public function sign($key, $password = null)
    {
        $this->signature = $this->getSigner()->sign($this->generateSigninInput(), $key, $password);
        $this->isSigned = true;

        return $this->signature;
    }

getSigner()是通过获取到加密类型,来实例化Namshi\JOSE\Signer下指定的类.项目中使用的就是Namshi\JOSE\Signer\OpenSSL\HS256类.这个类继承了HMAC父类,而HMAC就是具体signer的实现类

    public function sign($input, $key)
    {
        return hash_hmac($this->getHashingAlgorithm(), $input, (string) $key, true);
    }

这里的($this->generateSigninInput()就是payloadheader的内容 $keyJWT_SECRET的密匙 ,$password是非对称加密下签署令牌的密码.用于生成token的第三部分signature

生成token

$this->jws->getTokenString();

    public function getTokenString()
    {
        $signinInput = $this->generateSigninInput();

        return sprintf('%s.%s', $signinInput, $this->encoder->encode($this->getSignature()));
    }
    public function generateSigninInput()
    {
        $base64payload = $this->encoder->encode(json_encode($this->getPayload(), JSON_UNESCAPED_SLASHES));
        $base64header = $this->encoder->encode(json_encode($this->getHeader(), JSON_UNESCAPED_SLASHES));

        return sprintf('%s.%s', $base64header, $base64payload);
    }

先拼接了headerpayload 再拼接了Signature返回token

Tymon\JWTAuth\Providers\JWT\Lcobucci类也实现了token的生成,不同的是通过公钥和私钥来生成 token,这里流程不再赘述,代码如下:

    public function encode(array $payload)
    {
        // Remove the signature on the builder instance first.
        $this->builder->unsign();

        try {
            foreach ($payload as $key => $value) {
                $this->builder->set($key, $value);
            }
            $this->builder->sign($this->signer, $this->getSigningKey());
        } catch (Exception $e) {
            throw new JWTException('Could not create token: '.$e->getMessage(), $e->getCode(), $e);
        }

        return (string) $this->builder->getToken();
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Lumen是一个基于Laravel框架的微型PHP框架,它可以用于构建轻量级的API服务。而Dingo是一个在Laravel框架上构建API的工具包。JWT(JSON Web Token)是一种用于进行身份验证和授权的开放标准。 在使用Lumen结合Dingo和JWT进行开发时,需要先安装Lumen服务提供者、JWT和Dingo的组件。可以使用Composer来管理这些依赖。确保你的电脑上安装了Composer。 在Lumen,你可以使用控制器来处理请求。引用是一个示例UserController。在这个控制器,我们注入了JWTAuth实例,并使用它来处理用户的登录请求。其,我们首先获取请求的参数,然后使用这些参数进行条件查询。如果登录认证成功,我们会返回一个包含JWT令牌的JSON响应。 对于跨域问题,你可以使用palanik/lumen-cors来解决。引用提供了安装和配置palanik/lumen-cors的方法。你需要通过Composer来安装该组件,并在bootstrap/app.php文件添加cors路由间件。 以上就是关于Lumen、Dingo和JWT的一些基本信息和配置方法。如果你有关于它们的更具体的问题,请告诉我。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Lumen 配合 JWT + Dingo 开发流程](https://blog.csdn.net/qq_44149053/article/details/89444892)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *3* [lumen+dingo+jwt搭建api系统](https://blog.csdn.net/Chenlevin/article/details/111830096)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值