Laravel tymondesigns/jwt-auth 个问题
Laravel tymondesigns/jwt-auth problems
我正在使用 API 设置身份验证路由。
我正在使用 laravel 5.5 和 tymondesigns/jwt-auth 1.0.0-rc.1 以及 Postman 与 API.
进行交互
身份验证 route/method 似乎有效:
/**
* 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'));
}
邮递员 API post 请求 returns(似乎是)有效回复,例如:
{
"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',
],
];
谢谢
您收到令牌但未正确解析您需要检查令牌解析是否成功。
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';
});
]):
答案是:"this is not compatible with this feature in it's current state without extending it yourself".
我希望这对使用 UUID 作为主键的其他人有所帮助。如果不编辑供应商项目或扩展,您将无法做到这一点……但是,这是一个简单的解决方法。
我将向软件包作者提出这个问题,并希望找到一个更永久的解决方案。但是,这里有一个解决方法:
背景:
- UUID 在数据库中存储为二进制 (16)
id
列。
- 这不是人类 readable/text 友好。
- 为了解决这个问题,
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' => 'email'
会回避这个问题...结果不是。我会把这个反馈给作者
修改核心只是一个练习...我很确定这个 class 可以扩展,我很快就会尝试这个。在大多数情况下,编辑源当然不是最佳选择。
但是-我希望这次挖掘能帮助人们理解这个问题。
这是我在 API 中使用的解决方案,效果非常好。
首先重写 class 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 不变,并在您的自定义 class 中编写如下代码(如果适用)。
/**
* 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);
}
我正在使用 API 设置身份验证路由。 我正在使用 laravel 5.5 和 tymondesigns/jwt-auth 1.0.0-rc.1 以及 Postman 与 API.
进行交互身份验证 route/method 似乎有效:
/**
* 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'));
}
邮递员 API post 请求 returns(似乎是)有效回复,例如:
{
"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',
],
];
谢谢
您收到令牌但未正确解析您需要检查令牌解析是否成功。
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';
});
]):
答案是:"this is not compatible with this feature in it's current state without extending it yourself".
我希望这对使用 UUID 作为主键的其他人有所帮助。如果不编辑供应商项目或扩展,您将无法做到这一点……但是,这是一个简单的解决方法。
我将向软件包作者提出这个问题,并希望找到一个更永久的解决方案。但是,这里有一个解决方法:
背景:
- UUID 在数据库中存储为二进制 (16)
id
列。 - 这不是人类 readable/text 友好。
- 为了解决这个问题,
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' => 'email'
会回避这个问题...结果不是。我会把这个反馈给作者
修改核心只是一个练习...我很确定这个 class 可以扩展,我很快就会尝试这个。在大多数情况下,编辑源当然不是最佳选择。
但是-我希望这次挖掘能帮助人们理解这个问题。
这是我在 API 中使用的解决方案,效果非常好。
首先重写 class 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 不变,并在您的自定义 class 中编写如下代码(如果适用)。
/**
* 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);
}