Laravel Passport 通过访问令牌获取客户端 ID
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/44145080/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Laravel Passport Get Client ID By Access Token
提问by Walid Ammar
I'm writing a tiny sms gateway to be consumed by a couple of projects,
我正在编写一个小型短信网关,供几个项目使用,
I implemented laravel passport authentication (client credentials grant token)
我实现了 Laravel 护照身份验证(客户端凭据授予令牌)
Then I've added CheckClientCredentials
to api middleware group:
然后我添加CheckClientCredentials
到 api 中间件组:
protected $middlewareGroups = [
'web' => [
...
],
'api' => [
'throttle:60,1',
'bindings',
\Laravel\Passport\Http\Middleware\CheckClientCredentials::class
],
];
The logic is working fine, now in my controller I need to get client associated with a valid token.
逻辑工作正常,现在在我的控制器中,我需要获取与有效令牌相关联的客户端。
routes.php
路由文件
Route::post('/sms', function(Request $request) {
// save the sms along with the client id and send it
$client_id = ''; // get the client id somehow
sendSms($request->text, $request->to, $client_id);
});
For obvious security reasons I can never send the client id with the consumer request e.g. $client_id = $request->client_id;
.
出于明显的安全原因,我永远无法将客户端 ID 与消费者请求一起发送,例如$client_id = $request->client_id;
.
采纳答案by Walid Ammar
So, no answers ...
所以,没有答案...
I was able to resolve the issue by consuming my own API, finally I came up with simpler authentication flow, the client need to send their id & secret with each request, then I consumed my own /oauth/token
route with the sent credentials, inspired by Esben Petersenblog post.
我能够通过使用我自己的 API 来解决这个问题,最后我想出了更简单的身份验证流程,客户端需要在每个请求中发送他们的 id 和秘密,然后我使用/oauth/token
发送的凭据使用我自己的路由,灵感来自Esben Petersen博客文章。
Once the access token is generated, I append it to the headers of Symfony\Request
instance which is under processing.
生成访问令牌后,我将其附加到Symfony\Request
正在处理的实例的标头中。
My final output like this:
我的最终输出是这样的:
<?php
namespace App\Http\Middleware;
use Request;
use Closure;
class AddAccessTokenHeader
{
/**
* Octipus\ApiConsumer
* @var ApiConsumer
*/
private $apiConsumer;
function __construct() {
$this->apiConsumer = app()->make('apiconsumer');
}
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
$response = $this->apiConsumer->post('/oauth/token', $request->input(), [
'content-type' => 'application/json'
]);
if (!$response->isSuccessful()) {
return response($response->getContent(), 401)
->header('content-type', 'application/json');
}
$response = json_decode($response->getContent(), true);
$request->headers->add([
'Authorization' => 'Bearer ' . $response['access_token'],
'X-Requested-With' => 'XMLHttpRequest'
]);
return $next($request);
}
}
I used the above middleware in conjunction with Passport's CheckClientCredentials
.
我将上述中间件与 Passport 的CheckClientCredentials
.
protected $middlewareGroups = [
'web' => [
...
],
'api' => [
'throttle:60,1',
'bindings',
\App\Http\Middleware\AddAccessTokenHeader::class,
\Laravel\Passport\Http\Middleware\CheckClientCredentials::class
],
];
This way, I was able to insure that $request->input('client_id')
is reliable and can't be faked.
通过这种方式,我能够确保它$request->input('client_id')
是可靠的并且不能被伪造。
回答by bmatovu
I use this, to access the authenticated client app...
我用它来访问经过身份验证的客户端应用程序...
$bearerToken = $request->bearerToken();
$tokenId = (new \Lcobucci\JWT\Parser())->parse($bearerToken)->getHeader('jti');
$client = \Laravel\Passport\Token::find($tokenId)->client;
$client_id = $client->id;
$client_secret = $client->secret;
回答by Marsprobe
There is a tricky method. You can modify the method of handle in the middleware CheckClientCredentials, just add this line.
有一个棘手的方法。可以修改中间件CheckClientCredentials中的handle方法,只需要添加这一行即可。
$request["oauth_client_id"] = $psr->getAttribute('oauth_client_id');
Then you can get client_id in controller's function:
然后你可以在控制器的函数中获取client_id:
public function info(\Illuminate\Http\Request $request)
{
var_dump($request->oauth_client_id);
}
回答by Danny Ebbers
However the answer is quite late, i got some errors extracting the JTI header in Laravel 6.x because the JTI is no longer in the header, but only in the payload/claim. (Using client grants)
然而,答案已经很晚了,我在 Laravel 6.x 中提取 JTI 标头时遇到了一些错误,因为 JTI 不再位于标头中,而仅位于有效载荷/声明中。(使用客户赠款)
local.ERROR: Requested header is not configured {"exception":"[object] (OutOfBoundsException(code: 0): Requested header is not configured at /..somewhere/vendor/lcobucci/jwt/src/Token.php:112)
Also, adding it in a middleware was not an option for me. As i needed it on several places in my app.
此外,将它添加到中间件中对我来说不是一个选择。因为我在我的应用程序的几个地方需要它。
So i extended the original Laravel Passport Client (oauth_clients) model. And check the header as well as the payload. Allowing to pass a request, or use the request facade, if no request was passed.
所以我扩展了原始的 Laravel Passport Client (oauth_clients) 模型。并检查标头和有效载荷。如果没有请求通过,则允许传递请求,或使用请求门面。
<?php
namespace App\Models;
use Illuminate\Support\Facades\Request as RequestFacade;
use Illuminate\Http\Request;
use Laravel\Passport\Client;
use Laravel\Passport\Token;
use Lcobucci\JWT\Parser;
class OAuthClient extends Client
{
public static function findByRequest(?Request $request = null) : ?OAuthClient
{
$bearerToken = $request !== null ? $request->bearerToken() : RequestFacade::bearerToken();
$parsedJwt = (new Parser())->parse($bearerToken);
if ($parsedJwt->hasHeader('jti')) {
$tokenId = $parsedJwt->getHeader('jti');
} elseif ($parsedJwt->hasClaim('jti')) {
$tokenId = $parsedJwt->getClaim('jti');
} else {
Log::error('Invalid JWT token, Unable to find JTI header');
return null;
}
$clientId = Token::find($tokenId)->client->id;
return (new static)->findOrFail($clientId);
}
}
Now you can use it anywhere inside your laravel app like this:
现在你可以在你的 Laravel 应用程序中的任何地方使用它,如下所示:
If you have $request object available, (for example from a controller)
如果您有可用的 $request 对象,(例如来自控制器)
$client = OAuthClient::findByRequest($request);
Or even if the request is not available somehow, you can use it without, like this:
或者即使请求以某种方式不可用,您也可以不使用它,如下所示:
$client = OAuthClient::findByRequest();
Hopefully this useful for anyone, facing this issue today.
希望这对今天面临这个问题的任何人都有用。
回答by Adam Albright
The OAuth token and client information are stored as a protected variablein the Laravel\Passport\HasApiTokens trait (which you add to your User model).
OAuth 令牌和客户端信息作为受保护的变量存储在 Laravel\Passport\HasApiTokens 特征(您添加到用户模型中)中。
So simply add a getter method to your User modelto expose the OAuth information:
因此,只需在您的User 模型中添加一个 getter 方法来公开 OAuth 信息:
public function get_oauth_client(){
return $this->accessToken->client;
}
This will return an Eloquent model for the oauth_clients table
这将为 oauth_clients 表返回一个 Eloquent 模型
回答by James Wagoner
I dug into CheckClientCredentials class and extracted what I needed to get the client_id
from the token. aud
claim is where the client_id
is stored.
我深入研究了 CheckClientCredentials 类并提取了client_id
从令牌中获取所需的内容。aud
声明client_id
是存储的地方。
<?php
Route::middleware('client')->group(function() {
Route::get('/client-id', function (Request $request) {
$jwt = trim(preg_replace('/^(?:\s+)?Bearer\s/', '', $request->header('authorization')));
$token = (new \Lcobucci\JWT\Parser())->parse($jwt);
return ['client_id' => $token->getClaim('aud')];
});
});
Few places to refactor this to in order to easily access but that will be up to your application
很少有地方可以重构它以便轻松访问,但这取决于您的应用程序
回答by phnix
public function handle($request, Closure $next, $scope)
{
if (!empty($scope)) {
$psr = (new DiactorosFactory)->createRequest($request);
$psr = $this->server->validateAuthenticatedRequest($psr);
$clientId = $psr->getAttribute('oauth_client_id');
$request['oauth_client_id'] = intval($clientId);
}
return $next($request);
}
put above to your middleware file, then you can access client_id by request()->oauth_client_id
把上面放到你的中间件文件中,然后你可以通过访问client_id request()->oauth_client_id