我一直在尝试配置 LexikJWTAuthenticationBundle 以在基于 API 平台的项目中使用。
此 API 正在添加到使用 Sulu CMS (2.6.2) 和 Symfony (6.4.7) 的现有项目中。我正在使用 PHP 8.3 并安装并启用了 OpenSSL。
我希望能够使用 LexikJWTAuthenticationBundle 的网络令牌功能。我已经能够获得以下基于捆绑包默认设置的配置来工作:
lexik_jwt_authentication:
secret_key: '%env(resolve:JWT_SECRET_KEY)%'
public_key: '%env(resolve:JWT_PUBLIC_KEY)%'
pass_phrase: '%env(JWT_PASSPHRASE)%'
api_platform:
enabled: true
check_path: /api/login_check
username_path: username
password_path: password
encoder:
service: lexik_jwt_authentication.encoder.lcobucci
signature_algorithm: ES512
token_ttl: 3600
allow_no_expiration: false
clock_skew: 0
user_id_claim: username
token_extractors:
authorization_header:
enabled: true
prefix: Bearer
name: Authorization
cookie:
enabled: false
name: BEARER
query_parameter:
enabled: false
name: bearer
split_cookie:
enabled: false
cookies: { }
remove_token_from_body_when_cookies_used: true
set_cookies: { }
我已按照文档配置网络令牌功能。不幸的是,一旦我切换到使用
lexik_jwt_authentication.encoder.web_token
,一切都会崩溃。 JWT 令牌始终无效。
我编写了自己的用户提供程序服务以避免与 Sulu 发生冲突,并已验证它是否可以与捆绑包的默认编码器一起使用。
切换到网络令牌编码器后我的捆绑配置:
lexik_jwt_authentication:
secret_key: '%env(resolve:JWT_SECRET_KEY)%'
public_key: '%env(resolve:JWT_PUBLIC_KEY)%'
pass_phrase: '%env(JWT_PASSPHRASE)%'
api_platform:
enabled: true
check_path: /api/login_check
username_path: username
password_path: password
encoder:
service: lexik_jwt_authentication.encoder.web_token
signature_algorithm: ES512
token_ttl: 3600
allow_no_expiration: false
clock_skew: 0
user_id_claim: username
token_extractors:
authorization_header:
enabled: true
prefix: Bearer
name: Authorization
cookie:
enabled: false
name: BEARER
query_parameter:
enabled: false
name: bearer
split_cookie:
enabled: false
cookies: { }
remove_token_from_body_when_cookies_used: true
set_cookies: { }
access_token_issuance:
enabled: true
signature:
algorithm: ES512
key: # key
access_token_verification:
enabled: true
signature:
allowed_algorithms:
- ES512
keyset: # keyset
header_checkers: { }
claim_checkers:
- exp_with_clock_skew
- iat_with_clock_skew
- nbf_with_clock_skew
mandatory_claims: { }
blocklist_token:
enabled: false
cache: cache.app
我如何请求令牌:
curl -X POST http://localhost/api/login_check \
-H 'Content-Type: application/ld+json' \
-d '{"username":"someusername","password":"somepassword"}'
我收到令牌后发出的请求:
curl -H 'Accept: application/ld+json' \
-H 'Authorization: Bearer <token>' http://localhost/api/some-endpoint/4
我已经能够将问题追溯到令牌加载和解码的阶段。它已正确反序列化并分解为数组。在那之后它就会失败。这让我怀疑我的密钥编码有问题,但我不确定我做错了什么。
我已经使用
web-token/jwt-bundle
的命令来生成密钥,并且我尝试使用 独立 JWT 应用程序。我使用捆绑包的 key:analyze
和 keyset:analyze
命令分析了结果。他们似乎是正确的。我在这里查看了相关问题,看看其他人是否也遇到过类似的问题。不幸的是,这没有帮助。
我非常感谢任何人对此有任何见解。我确实碰壁了。预先感谢!
编辑: 经过更多调试后,如果使用网络令牌功能,该捆绑包似乎必须加密,即使文档另有说明。由于我没有配置加密,因此由于未定义的算法,我使用令牌的所有请求都被拒绝。
加密有效,但解密无效。它到达过程的解密部分,然后失败。所以,我仍然收到
Invalid JWT Token
回复。
我启用加密的完整配置:
lexik_jwt_authentication:
secret_key: '%env(resolve:JWT_PRIVATE_KEY)%'
public_key: '%env(resolve:JWT_PUBLIC_KEY)%'
pass_phrase: '%env(JWT_PASSPHRASE)%'
api_platform:
enabled: true
check_path: /api/login_check
username_path: username
password_path: password
encoder:
service: lexik_jwt_authentication.encoder.web_token
signature_algorithm: ES512
token_ttl: 3600
allow_no_expiration: false
clock_skew: 0
user_id_claim: username
token_extractors:
authorization_header:
enabled: true
prefix: Bearer
name: Authorization
cookie:
enabled: false
name: BEARER
query_parameter:
enabled: false
name: bearer
split_cookie:
enabled: false
cookies: { }
remove_token_from_body_when_cookies_used: true
set_cookies: { }
access_token_issuance:
enabled: true
signature:
algorithm: ES512
key: # key
encryption:
enabled: true
key_encryption_algorithm: RSA-OAEP-256
content_encryption_algorithm: A256CBC-HS512
key: # key
access_token_verification:
enabled: true
signature:
allowed_algorithms:
- ES512
keyset: # keyset
header_checkers: { }
claim_checkers:
- exp_with_clock_skew
- iat_with_clock_skew
- nbf_with_clock_skew
mandatory_claims: { }
encryption:
enabled: true
continue_on_decryption_failure: false
header_checkers:
- iat_with_clock_skew
- nbf_with_clock_skew
- exp_with_clock_skew
allowed_key_encryption_algorithms:
- RSA-OAEP-256
allowed_content_encryption_algorithms:
- A256CBC-HS512
keyset: # keyset
blocklist_token:
enabled: false
cache: cache.app
当我最初发布这个问题时,我不确定我遇到的问题是错误还是配置问题。我也在官方存储库中打开了一个问题。
今天我能够更深入地研究这个问题,它确实似乎是一个错误。我在 GitHub 问题中发布了解决方法以及其他信息。但为了让那些只想要一个可行的解决方案而不需要其他细节的人保持完整,我也会将其发布在这里。
作为修复 bug 之前的解决方法,我通过实现
Kernel
来扩展我的 CompilerPassInterface
类,如 Symfony 文档如何使用编译器通道中所述。使用 null
覆盖默认加密配置值可防止引发异常,并允许访问令牌颁发和验证正常工作。
请注意,此解决方法仅在您不使用加密时才有效。我仍然无法进行解密。但这是一个单独的问题。
// src/Kernel.php
namespace App;
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Kernel as BaseKernel;
class Kernel extends BaseKernel implements CompilerPassInterface
{
use MicroKernelTrait;
// ...
public function process(ContainerBuilder $container): void
{
$accessTokenBuilderService = 'lexik_jwt_authentication.access_token_builder';
$accessTokenLoaderService = 'lexik_jwt_authentication.access_token_loader';
if ($container->hasDefinition($accessTokenBuilderService)) {
$container->getDefinition($accessTokenBuilderService)
->replaceArgument(5, null)
->replaceArgument(6, null)
->replaceArgument(7, null);
}
if ($container->hasDefinition($accessTokenLoaderService)) {
$container->getDefinition($accessTokenLoaderService)
->replaceArgument(9, null)
->replaceArgument(10, null)
->replaceArgument(11, null)
->replaceArgument(12, null);
}
}
// ...
}
以下示例配置适用于上述
Kernel
实现。根据需要进行更改。
# config/services.yaml
parameters:
# ...
env(SIGNATURE_KEY): '%kernel.project_dir%/config/jwt/signature.jwk'
env(SIGNATURE_KEYSET): '%kernel.project_dir%/config/jwt/signature.jwkset'
# config/packages/lexik_jwt_authentication.yaml
lexik_jwt_authentication:
secret_key: '%env(resolve:JWT_PRIVATE_KEY)%'
public_key: '%env(resolve:JWT_PUBLIC_KEY)%'
pass_phrase: '%env(JWT_PASSPHRASE)%'
api_platform:
enabled: true
check_path: /api/login_check
username_path: username
password_path: password
encoder:
service: lexik_jwt_authentication.encoder.web_token
token_ttl: 3600
allow_no_expiration: false
clock_skew: 0
user_id_claim: username
token_extractors:
authorization_header:
enabled: true
prefix: Bearer
name: Authorization
cookie:
enabled: false
name: BEARER
query_parameter:
enabled: false
name: bearer
split_cookie:
enabled: false
cookies: { }
remove_token_from_body_when_cookies_used: true
set_cookies: { }
access_token_issuance:
enabled: true
signature:
algorithm: RS256
key: '%env(file:SIGNATURE_KEY)%'
access_token_verification:
enabled: true
signature:
allowed_algorithms:
- RS256
keyset: '%env(file:SIGNATURE_KEYSET)%'
header_checkers: { }
claim_checkers:
- exp_with_clock_skew
- iat_with_clock_skew
- nbf_with_clock_skew
mandatory_claims: { }
blocklist_token:
enabled: false
cache: cache.app