【问题标题】:Laravel tymondesigns/jwt-auth problemsLaravel tymondesigns/jwt-auth 问题
【发布时间】:2018-03-30 06:15:27
【问题描述】:

我正在使用我的 API 设置身份验证路由。 我正在使用 laravel 5.5 与 tymondesigns/jwt-auth 1.0.0-rc.1 和 Postman 来与 API 交互。

身份验证路由/方法似乎有效:

/**
 * Authenticates a json request, generating a token.
 *
 * @param Request $request
 * @return JsonResponse
 */
public function authenticate(Request $request)
{
    // grab credentials from the request
    $credentials = $request->only('email', 'password');

    try {
        // attempt to verify the credentials and create a token for the user
        if (! $token = JWTAuth::attempt($credentials)) {
            return response()->json(
                [
                    'error' => 'Invalid credentials.',
                    'detail' => 'Please use your email and password to generate a token.'
                ],
                401);
        }
    } catch (JWTException $e) {
        // something went wrong whilst attempting to encode the token
        return response()->json(
            [
                'error' => 'Could not create token',
                'detail' => 'There was an internal problem and your token could not be created.'
            ], 500
        );
    }

    // all good so return the token
    return response()->json(compact('token'));
}

Postman API 发布请求返回(似乎是)有效响应,例如:

{
    "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vc29sZGVyc3RhcmFwaS5jb20ubG9jYWwvYXBpL2F1dGhlbnRpY2F0ZSIsImlhdCI6MTUwNzg4NjU2OSwiZXhwIjoxNTA3ODkwMTY5LCJuYmYiOjE1MDc4ODY1NjksImp0aSI6IkpFWjBkc0dNbEVydXRHcFciLCJzdWIiOiIwNzk2MjhDMC03QjBDLTExRTYtODRERC1DQjAzMzVGN0JBNUQiLCJwcnYiOiI4N2UwYWYxZWY5ZmQxNTgxMmZkZWM5NzE1M2ExNGUwYjA0NzU0NmFhIn0.Dl2EEaYZx3H5XXG9WUcPXYKuma0ZjCvcCsb99hgB6O4"
}

首先,出于基本测试目的,我将其提供给使用 GET 的操作,并带有以下后缀:

?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vc29sZGVyc3RhcmFwaS5jb20ubG9jYWwvYXBpL2F1dGhlbnRpY2F0ZSIsImlhdCI6MTUwNzg4NjU2OSwiZXhwIjoxNTA3ODkwMTY5LCJuYmYiOjE1MDc4ODY1NjksImp0aSI6IkpFWjBkc0dNbEVydXRHcFciLCJzdWIiOiIwNzk2MjhDMC03QjBDLTExRTYtODRERC1DQjAzMzVGN0JBNUQiLCJwcnYiOiI4N2UwYWYxZWY5ZmQxNTgxMmZkZWM5NzE1M2ExNGUwYjA0NzU0NmFhIn0.Dl2EEaYZx3H5XXG9WUcPXYKuma0ZjCvcCsb99hgB6O4

为了测试这一点,如果我执行以下操作:

public function globalObjects(Request $request): JsonResponse {
    var_dump(JWTAuth::parseToken()->authenticate(), JWTAuth::getToken()); exit;

   // ... later code that never gets reached
}

我得到以下信息:

bool(false) object(Tymon\JWTAuth\Token)#809 (1) { ["value":"Tymon\JWTAuth\Token":private]=> string(384) "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vc29sZGVyc3RhcmFwaS5jb20ubG9jYWwvYXBpL2F1dGhlbnRpY2F0ZSIsImlhdCI6MTUwNzg4NjU2OSwiZXhwIjoxNTA3ODkwMTY5LCJuYmYiOjE1MDc4ODY1NjksImp0aSI6IkpFWjBkc0dNbEVydXRHcFciLCJzdWIiOiIwNzk2MjhDMC03QjBDLTExRTYtODRERC1DQjAzMzVGN0JBNUQiLCJwcnYiOiI4N2UwYWYxZWY5ZmQxNTgxMmZkZWM5NzE1M2ExNGUwYjA0NzU0NmFhIn0.Dl2EEaYZx3H5XXG9WUcPXYKuma0ZjCvcCsb99hgB6O4" }

.. 如:

  • 我收到令牌
  • 找不到用户

注意事项:

  • 我的主键是id,但它是一个UUID,所以是一个二进制(16)......因此:
  • 我将标识符设置为:'identifier' => 'email'

以下请求:这里是\config\jwt.php

return [
    'secret' => env('JWT_SECRET', 'AqAWUTYISA56lrl2vcRtZQn4M4zk9onl'),
    'ttl' => 60,
    'refresh_ttl' => 20160,
    'algo' => 'HS256',
    'user' => 'App\User',
    'identifier' => 'email',
    'required_claims' => ['iss', 'iat', 'exp', 'nbf', 'sub', 'jti'],
    'blacklist_enabled' => env('JWT_BLACKLIST_ENABLED', true),
    'providers' => [
        'user' => 'Tymon\JWTAuth\Providers\User\EloquentUserAdapter',
        'jwt' => 'Tymon\JWTAuth\Providers\JWT\Namshi',
        'auth' => 'Tymon\JWTAuth\Providers\Auth\Illuminate',
        'storage' => 'Tymon\JWTAuth\Providers\Storage\Illuminate',

    ],

];

谢谢

【问题讨论】:

  • 发送带有 Header 的令牌
  • @mohammad 令牌正在通过 GET 发送。正在处理令牌。您可以在 Tymon\JWTAuth\Token 对象的 var_dump 中看到它。
  • 请添加您的 JWT 配置文件。
  • 按要求添加了 jwt.php。

标签: laravel jwt-auth


【解决方案1】:

这是我在 API 中使用的解决方案,效果非常好。

先重写类Tymon\JWTAuth\Providers\Auth\Illuminate::class

<?php


namespace Scryba\Code\Laravel\Providers\Auth\Jwt;

use Tymon\JWTAuth\Contracts\Providers\Auth;
use Illuminate\Contracts\Auth\Guard as GuardContract;

class Illuminate implements Auth
{
/**
 * The authentication guard.
 *
 * @var \Illuminate\Contracts\Auth\Guard
 */
protected $auth;

/**
 * Constructor.
 *
 * @param  \Illuminate\Contracts\Auth\Guard  $auth
 *
 * @return void
 */
public function __construct(GuardContract $auth)
{
    $this->auth = $auth;
}

/**
 * Check a user's credentials.
 *
 * @param  array  $credentials
 *
 * @return bool
 */
public function byCredentials(array $credentials)
{
    return $this->auth->once($credentials);
}

/**
 * Authenticate a user via the id.
 *
 * @param  mixed  $id
 *
 * @return bool
 */
public function byId($id)
{
    //you can see i added hex2bin($id)because i save my UUID primary key as 
    //binary(16)
    return $this->auth->onceUsingId(hex2bin($id));
}

/**
 * Get the currently authenticated user.
 *
 * @return mixed
 */
public function user()
{
    return $this->auth->user();
}
}

然后将\config\jwt.php文件更新为

 'providers' => [

    /*
    |--------------------------------------------------------------------------
    | JWT Provider
    |--------------------------------------------------------------------------
    |
    | Specify the provider that is used to create and decode the tokens.
    |
    */

    'jwt' => Tymon\JWTAuth\Providers\JWT\Namshi::class,

    /*
    |--------------------------------------------------------------------------
    | Authentication Provider
    |--------------------------------------------------------------------------
    |
    | Specify the provider that is used to authenticate users.
    |
    */

    //'auth' => Tymon\JWTAuth\Providers\Auth\Illuminate::class,
    'auth' => Scryba\Code\Laravel\Providers\Auth\Jwt\Illuminate::class,

    /*
    |--------------------------------------------------------------------------
    | Storage Provider
    |--------------------------------------------------------------------------
    |
    | Specify the provider that is used to store tokens in the blacklist.
    |
    */

    'storage' => Tymon\JWTAuth\Providers\Storage\Illuminate::class,

],

在我的路线文件中

////// Protected methods (requires Authenticatication)
        $api->group(
            [
                'middleware' => ['api.auth'],
                'providers' => ['jwt'],

            ],function($api){

        $api->resource('cars', 'CarController', ['only' => [
            'index' ,'show'
        ]]);

        });

因此,在您的情况下,请保留源文件 \vendor\tymon\jwt-auth\src\JWTAuth.php 并在您的自定义类中编写您的代码(如果适用)。

/**
* Authenticate a user via the id.
*
* @param  mixed  $id
*
* @return bool
*/
public function byId($id)
{
   $id_text = $this->getPayload()->get('sub');

   $uuid_helper = new UuidHelper();
   $id = $uuid_helper->textIdToId($id_text);

  return $this->auth->onceUsingId($id);
}

【讨论】:

    【解决方案2】:

    您的令牌已收到但未正确解析,您需要检查令牌解析是否成功。

    if (! $auth = JWTAuth::parseToken();) {
        throw Exception('JWTAuth unable to parse token from request');
    }
    dd(\Auth::id());
    

    我建议你去你的 kernal.php 并在受保护的 $routeMiddleware 数组中添加以下行

    'jwt.auth' => 'Tymon\JWTAuth\Middleware\GetUserFromToken',
    'jwt.refresh' => 'Tymon\JWTAuth\Middleware\RefreshToken',
    

    然后去你的路由并像中间件一样使用它来进行身份验证

     Route::group(['middleware' => 'jwt.auth'], function () {
      // Your routes here that you want to protect
            Route::get('foo', function () {
            return 'Hello World';
                 });
         ]):
    

    【讨论】:

    • 令牌解析正确(无异常); dd()(或 var_dump())的结果是 null。感谢您对中间件的建议,我打算这样做,但现在我只想让一个动作完全工作。
    【解决方案3】:

    答案是:“如果不自行扩展,这与当前状态下的此功能不兼容”。

    我希望这可以帮助其他使用 UUID 作为主键的人。如果不编辑供应商项目或扩展,您将无法做到这一点……但是,这是一个简单的解决方法。

    我将与包作者一起提出这个问题,并希望找到一个更持久的解决方案。但是,这里有一个解决方法:

    背景:

    • UUID 在数据库中存储为二进制 (16) id 列。
    • 这不是人类可读/文本友好的。
    • 为了解决这个问题,id_text 字段作为自动生成的 mysql 字段存在
    • 注意 - 你永远不应该使用这些搜索(它会给数据库带来很大压力)
    • 这些是文本可读的,因此......可以很容易地用于表单等
    • 我创建了一个 UuidHelper 以便于翻译

    JWT 中的问题:

    • 身份验证函数尝试将 id_text 解码为 id
    • 显然,这总是失败

    在文件\vendor\tymon\jwt-auth\src\JWTAuth.php

    /**
     * Authenticate a user via a token.
     *
     * @return \Tymon\JWTAuth\Contracts\JWTSubject|false
     */
    public function authenticate()
    {
        $id_text = $this->getPayload()->get('sub');
    
        $uuid_helper = new UuidHelper();
        $id = $uuid_helper->textIdToId($id_text);
    
        if (! $this->auth->byId($id)) {
            return false;
        }
    
        return $this->user();
    }
    

    文档不是最清楚的,所以我假设'identifier' =&gt; 'email' 会回避这个问题……结果不是。我会把这个反馈给作者

    修改核心只是一个练习......我很确定这个类可以扩展,我很快就会尝试这个。在大多数情况下,编辑源当然不是最佳选择。

    但是 - 我希望这次挖掘能够帮助人们理解问题。

    【讨论】:

      猜你喜欢
      • 2020-01-08
      • 2020-03-20
      • 2015-06-28
      • 2016-01-30
      • 2015-06-20
      • 1970-01-01
      • 2018-03-22
      • 2016-12-21
      • 2018-10-06
      相关资源
      最近更新 更多