使用 Laravel 验证第三方 JWT

问题描述 投票:0回答:3

我正在使用外部身份提供程序对用户进行身份验证,创建了 SPA 客户端(获得

client_id
client_secret
),使用
audience
scope
配置 API,因此一旦用户通过身份验证,他们将获得
access_token
(将被授权)访问多个自定义微服务(API)。

当我的自定义 API 收到带有不记名访问令牌 (JWT) 的请求时,要做的第一件事就是验证令牌。为了验证 JWT,我需要执行以下步骤:

  1. 检查 JWT 格式是否正确(解析 JWT)
  2. 检查签名。我的外部身份提供商仅通过 JWKS(JSON Web 密钥集)URL (https://{domain}/.well-known/jwks.json) 支持 RS256,因此我可以通过此 URL 获取我的公钥。
  3. 验证标准声明
  4. 检查应用程序权限(范围)

有很多包/库(即https://github.com/tymondesigns/jwt-auth)来创建 JWT 令牌,但我找不到任何包/库来使用上述步骤来验证它。任何人都可以帮助找到合适的 Laravel/PHP 包/库,或者让我走向正确的方向以实现我的目标(尤其是第 2 点)。

php laravel jwt
3个回答
1
投票

我过去做过类似的事情,我不知道这是否有帮助,但我会尝试一下。要使用公钥,您应该下载它,将其放在磁盘上的某个位置(例如

storage/jwt/public.pem
),然后将其在jwt配置
config/jwt.php
中与ALGO链接(您可以在此处查看支持的算法

    'keys' => [
        // ...    
        'public' => 'file://'.storage_path('jwt/public.pem'),
        // ...
    ],
    'algo' => 'RS256', 

然后,你应该有一个自定义的 Guard,我们称之为 JWTGuard:

<?php
namespace App\Guard;use App\Models\User;
use Illuminate\Auth\GuardHelpers;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Http\Request;
use Tymon\JWTAuth\JWT;class JWTGuard implements Guard
{
    use GuardHelpers;       
    /**
     * @var JWT $jwt
     */
    protected JWT $jwt;       
    /**
     * @var Request $request
     */
    protected Request $request;    
    /**
     * JWTGuard constructor.
     * @param JWT $jwt
     * @param Request $request
     */
    public function __construct(JWT $jwt, Request $request) {
        $this->jwt = $jwt;
        $this->request = $request;
    }       
    public function user() {
        if (! is_null($this->user)) {
            return $this->user;
        }           
        if ($this->jwt->setRequest($this->request)->getToken() && $this->jwt->check()) {
            $id = $this->jwt->payload()->get('sub');               
            $this->user = new User();
            $this->user->id = $id;
            // Set data from custom claims               
            return $this->user;
        }
        return null;
    }       
    public function validate(array $credentials = []) {    }
}

这应该完成所有的验证逻辑,我使用了自定义用户实现,类签名如下:

use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Database\Eloquent\Model;
class User extends Model implements AuthenticatableContract {
    // custom implementation
}

最后,您应该在 AuthServiceProvider 和 auth 配置中注册守卫

public function boot()
{
  $this->registerPolicies();  
  $this->app['auth']->extend(
    'jwt-auth', 
    function ($app, $name, array $config) {
      $guard = new JWTGuard(
        $app['tymon.jwt'],
        $app['request']
      );      
      $app->refresh('request', $guard, 'setRequest');      
      return $guard;
    }
  );
}

然后在配置中允许它

<?php
return [
 'defaults' => [
        'guard' => 'jwt',
        'passwords' => 'users',
    ],
 'guards' => [
        // ...
        'jwt' => [
            'driver' => 'jwt-auth',
            'provider' => 'users'
        ],
    ],
 // ...
];

然后您可以将其用作中间件,如下所示:

Route::middleware('auth:jwt')->get('/user', function() {
    return Auth::user();
}

这听起来不错吗?


0
投票

最后我使用了 Laravel 的 Auth0 SDK - https://auth0.com/docs/quickstart/backend/laravel/01-authorization。漂亮干净的解决方案。


0
投票

对于

PHP
Laravel
来说,网上关于这个主题的帮助并不多。经过大量的试验和错误,我成功地使用
JWT Token
验证了
firebase/php-jwt
。并将解决方案放在这里,以便将来其他人可以轻松实现它。

use Firebase\JWT\JWT;
use Firebase\JWT\JWK;
use Illuminate\Support\Facades\Log; 

//...

function validateJwtToken($jwt) {
    // split the jwt
    $tokenParts = explode('.', $jwt);
    $header = base64_decode($tokenParts[0]);
    $payload = json_decode(base64_decode($tokenParts[1]));

    // The below approach can be used to extract the key from the payload
    // You need to know which one exactly is the valid public key combination
    // For me it was on 0 index, but for better clarity, I've placed the key below
    // $jwk = (array)$payload->keys[0];

    $jwk = [
        'kty' => 'EC',
        'use' => 'sig',
        'crv' => 'P-256',
        'kid' => 'codilityhub-tu-es',
        'x'   => '9RZnkUM0uvAEMZfaF...',
        'y'   => 'lsKEv2uHKSFn2bkZV...',
        'alg' => 'ES256' //in your case the algo may be different
    ];

    try {
        // Verifies JWT token and return details otherwise raises SignatureInvalidException exception
        $decoded = JWT::decode($jwt, JWK::parseKey($jwk));
        return true;
    } catch(\Firebase\JWT\SignatureInvalidException $sigE) {
        Log::error("Error occured in verifyJwtToken details " . $sigE->getMessage());
        return false;
    }
}
//...

来自jwt.io的一些屏幕截图,您可以从中识别您的令牌是否有效。如果有效,上述方法会在代码中执行完全相同的验证。

以下是在 jwt.io 中验证令牌的步骤。

步骤1

选择正确的算法,然后将

JWT Token
复制并粘贴到 jwt.io 中。

第2步

识别正确的密钥并复制相应的

JSON
Step 3
。请记住针对此键的代码中的
$jwk
变量调整逻辑。

第3步

将从

JSON
复制的
Step 2
粘贴到jwt.io的
verify signature
中。

如果答案有帮助,请竖起大拇指。

快乐编码:)

© www.soinside.com 2019 - 2024. All rights reserved.