如何使用纯令牌(令牌作为字符串)从控制器 $jwtManager->decode($jwt) 解析 jwt 令牌

Posted

技术标签:

【中文标题】如何使用纯令牌(令牌作为字符串)从控制器 $jwtManager->decode($jwt) 解析 jwt 令牌【英文标题】:How to parse the jwt token from controller $jwtManager->decode($jwt) using pure token ( token as a string ) 【发布时间】:2019-02-06 01:46:19 【问题描述】:

所以我正在使用 Lexik JWT 身份验证包 (Symfony 2.6) 并使用此代码成功创建了用户和令牌:

$userRegistration = new UserRegistration();
$userRegistration->setPassword($request->request->get('password'));
$userRegistration->setEmail($request->request->filter('email'));
$userRegistration->setName($request->request->filter('name'));

$token = $this->jwtManager->create($RegisteredUser);
return $this->responseProvider->ok((object) [
    'userId' => $RegisteredUser->getId(),
    'token' => $token
]);

回应:

"data": 
    "userId": 24,
    "token": "eyJhbGciOiJSUzI1NiJ9.eyJyb2xlcyI6WyJST0xFX1VTRVIiXSwidXNlcm5hbWUiOiJqYWdhZHVAaHViaWktbmV0d29yay5jb20iLCJleHAiOjE1MzYxNTI0MDAsImlhdCI6MTUzNTU0NzYwMH0.B7gnfGdW1ijAIlo9xUI0DwkGaajQAQPBkRx4ChILXRNtpLdwgEl_9gvWdiidFbSXJseS8jslOfuAFUIWATmbNBoWVa3nc8SxkIrKI29xZuN6hB7R-63RH2BKsAVPsEjgTIJoqkkCrfrSum-_d3LEf36jcXqZb8M-GRKI477IwSDDwG_7YK5v0mu8N4TATXhN0tZGNYxp8Y27EI-g0Gmj9BIiobxnqVVoBWHN5J8d-UCrXRq94ifhEiQBxkG9r_eacMscB80n1VsiN2ouKH2kX-HRxRJmcgmydxvR7RcEW-P6koTxkaZJGO6mv7auSudTFlDENpwD4OD7gtn_wMUDS_OuN8WT7rZp8lwKY9f8J9fiGyq5J-8C_HmyjW-h8WhuJmTUaKhCZ-eLgDm4Vs2IQGYkHJEDFumnIZ607MAa1CW1ChAvurqvUqJ3G4TTN4wYqAHpSKz4y8SAMLjO91cedBPH6K5i9lh5htF-mW_htem7e5ornicU_djSccgHbxfXHQYTHCnqLp7-ONfl_p4nmhIEK0wcF0gkBXbIitzeTjy7C_uf_FV1sLPE5cY3PUP42DmHrG4PuXHLv_L1EjErkrpna7pChKA_TPeiZjqMcQoE70sZw8rr8KnRF2hpABdU_M2ZXOt_vF5-T8mLmKqs0LHxE089vVC3xsAh0mUr4FE"
 

当我尝试使用jwtManager->decode 方法解码其他控制器中的当前令牌时,问题开始了:

$jwt = "eyJhbGciOiJSUzI1NiJ9.eyJyb2xlcyI6WyJST0xFX1VTRVIiXSwidXNlcm5hbWUiOiJqYWdhZHVAaHViaWktbmV0d29yay5jb20iLCJleHAiOjE1MzYxNTI0MDAsImlhdCI6MTUzNTU0NzYwMH0.B7gnfGdW1ijAIlo9xUI0DwkGaajQAQPBkRx4ChILXRNtpLdwgEl_9gvWdiidFbSXJseS8jslOfuAFUIWATmbNBoWVa3nc8SxkIrKI29xZuN6hB7R-63RH2BKsAVPsEjgTIJoqkkCrfrSum-_d3LEf36jcXqZb8M-GRKI477IwSDDwG_7YK5v0mu8N4TATXhN0tZGNYxp8Y27EI-g0Gmj9BIiobxnqVVoBWHN5J8d-UCrXRq94ifhEiQBxkG9r_eacMscB80n1VsiN2ouKH2kX-HRxRJmcgmydxvR7RcEW-P6koTxkaZJGO6mv7auSudTFlDENpwD4OD7gtn_wMUDS_OuN8WT7rZp8lwKY9f8J9fiGyq5J-8C_HmyjW-h8WhuJmTUaKhCZ-eLgDm4Vs2IQGYkHJEDFumnIZ607MAa1CW1ChAvurqvUqJ3G4TTN4wYqAHpSKz4y8SAMLjO91cedBPH6K5i9lh5htF-mW_htem7e5ornicU_djSccgHbxfXHQYTHCnqLp7-ONfl_p4nmhIEK0wcF0gkBXbIitzeTjy7C_uf_FV1sLPE5cY3PUP42DmHrG4PuXHLv_L1EjErkrpna7pChKA_TPeiZjqMcQoE70sZw8rr8KnRF2hpABdU_M2ZXOt_vF5-T8mLmKqs0LHxE089vVC3xsAh0mUr4FE";
$test = $this->jwtManager->decode($jwt);

但是JWTManager::decode() 必须实现接口Symfony\Component\Security\Core\Authentication\Token\TokenInterface 并且不期望给出字符串。

我的目标只是从这个令牌中获取 userId,但找不到如何解码令牌的任何信息。有谁知道如何简单地解码令牌?

【问题讨论】:

【参考方案1】:

请在没有任何库的情况下找到我的代码。

function decodeJWTPayloadOnly($token)
        $tks = explode('.', $token);
        if (count($tks) != 3) 
            return null;
        
        list($headb64, $bodyb64, $cryptob64) = $tks;
        $input=$bodyb64;
        $remainder = strlen($input) % 4;
        if ($remainder) 
            $padlen = 4 - $remainder;
            $input .= str_repeat('=', $padlen);
        
        $input = (base64_decode(strtr($input, '-_', '+/')));

        if (version_compare(php_VERSION, '5.4.0', '>=') && !(defined('JSON_C_VERSION') && PHP_INT_SIZE > 4)) 
            $obj = json_decode($input, false, 512, JSON_BIGINT_AS_STRING);
         else 
            $max_int_length = strlen((string) PHP_INT_MAX) - 1;
            $json_without_bigints = preg_replace('/:\s*(-?\d'.$max_int_length.',)/', ': "$1"', $input);
            $obj = json_decode($json_without_bigints);
        
        return $obj;

【讨论】:

【参考方案2】:

在不使用 JWT 库的情况下手动从令牌中获取信息非常简单。

一个 JWT 字符串由 3 部分组成: base64url 编码的标头和有效负载都是 JSON“对象”和签名。所有 3 个部分都由 . 分隔。

因此,您只需将令牌拆分为 3 个部分,在此处使用 explode 完成,然后解码 base64url 编码字符串 (base64_decode),最后解码 JSON (json_decode):

$token = "eyJhbGciOiJSUzI1NiJ9.eyJyb2xlcyI6WyJST0xFX1VTRVIiXSwidXNlcm5hbWUiOiJqYWdhZHVAaHViaWktbmV0d29yay5jb20iLCJleHAiOjE1MzYxNTI0MDAsImlhdCI6MTUzNTU0NzYwMH0.B7gnfGdW1ijAIlo9xUI0DwkGaajQAQPBkRx4ChILXRNtpLdwgEl_9gvWdiidFbSXJseS8jslOfuAFUIWATmbNBoWVa3nc8SxkIrKI29xZuN6hB7R-63RH2BKsAVPsEjgTIJoqkkCrfrSum-_d3LEf36jcXqZb8M-GRKI477IwSDDwG_7YK5v0mu8N4TATXhN0tZGNYxp8Y27EI-g0Gmj9BIiobxnqVVoBWHN5J8d-UCrXRq94ifhEiQBxkG9r_eacMscB80n1VsiN2ouKH2kX-HRxRJmcgmydxvR7RcEW-P6koTxkaZJGO6mv7auSudTFlDENpwD4OD7gtn_wMUDS_OuN8WT7rZp8lwKY9f8J9fiGyq5J-8C_HmyjW-h8WhuJmTUaKhCZ-eLgDm4Vs2IQGYkHJEDFumnIZ607MAa1CW1ChAvurqvUqJ3G4TTN4wYqAHpSKz4y8SAMLjO91cedBPH6K5i9lh5htF-mW_htem7e5ornicU_djSccgHbxfXHQYTHCnqLp7-ONfl_p4nmhIEK0wcF0gkBXbIitzeTjy7C_uf_FV1sLPE5cY3PUP42DmHrG4PuXHLv_L1EjErkrpna7pChKA_TPeiZjqMcQoE70sZw8rr8KnRF2hpABdU_M2ZXOt_vF5-T8mLmKqs0LHxE089vVC3xsAh0mUr4FE";

$tokenParts = explode(".", $token);  
$tokenHeader = base64_decode($tokenParts[0]);
$tokenPayload = base64_decode($tokenParts[1]);
$jwtHeader = json_decode($tokenHeader);
$jwtPayload = json_decode($tokenPayload);
print $jwtPayload->username;

在最后一行你有想要的信息。

您还可以在https://jwt.io 上检查您的令牌,以查看有效负载中包含哪些字段。在那个网站上也有关于 JWT 的很好的介绍。

【讨论】:

在解码前应该检查令牌是否有效,否则会给出一些偏移错误。【参考方案3】:

您可以为此使用 JWTEncoder 服务。 服务名称为lexik_jwt_authentication.jws_provider.lcobucci

或者如果你想要类命名服务使用Lexik\Bundle\JWTAuthenticationBundle\Encoder\JWTEncoderInterface

你要找的方法是decode()

$jwtEncoder->decode($yourToken);

【讨论】:

但是如果 JWT 过期了,decode() 会抛出 Exception : ( 然后捕获异常.. :) 你不会使用无效的、过期的令牌。

以上是关于如何使用纯令牌(令牌作为字符串)从控制器 $jwtManager->decode($jwt) 解析 jwt 令牌的主要内容,如果未能解决你的问题,请参考以下文章

如何在控制器方法中使 JWT 令牌授权可选

如何模拟 JWT 令牌以将其与 Mockito 和 Spring Boot 一起使用

使用 JWT 令牌的 jti 声明作为不透明令牌

如何从 Flask 返回不记名 JWT 令牌?

身份验证后请求其他服务时如何从 JWT 令牌获取用户名?

如何从 Node.js 中的 jwt 令牌获取 user.id?