我如何使用 LexikJWTAuthenticationBundle 通过自定义 jwt 令牌生成来实现刷新令牌?
How i can implement refresh token with custom jwt token generation with LexikJWTAuthenticationBundle?
目前我在 api 平台中创建带有自定义 symfony 控制器的 jwt 令牌,提供者并使用 JWTEncoderInterface 进行编码,使用来自外部 api 的身份验证。我的数据库中有用户但没有密码。如何使用该系统实现刷新令牌?
security.yml
providers:
# used to reload user from session & other features (e.g. switch_user)
user_provider:
id: App\Security\UserProvider
firewalls:
dev:
pattern: ^/_(profiler|wdt)
security: false
api:
pattern: ^/api/
stateless: true
anonymous: true
provider: user_provider
guard:
authenticators:
- app.authenticator
main:
anonymous: true
stateless: true
pattern: /authentication_token
我的验证器
<?php
namespace App\Security\Guard;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Guard\AbstractGuardAuthenticator;
use Lexik\Bundle\JWTAuthenticationBundle\Encoder\JWTEncoderInterface;
use Throwable;
class Authenticator extends AbstractGuardAuthenticator
{
private JWTEncoderInterface $jwtEncoder;
public function __construct(JWTEncoderInterface $jwtEncoder)
{
$this->jwtEncoder = $jwtEncoder;
}
/**
* Called on every request to decide if this authenticator should be
* used for the request. Returning `false` will cause this authenticator
* to be skipped.
*/
public function supports(Request $request) : bool
{
return $request->headers->has('Authorization Bearer');
}
/**
* Called on every request. Return whatever credentials you want to
* be passed to getUser() as $credentials.
*/
public function getCredentials(Request $request) : string
{
return $request->headers->get('Authorization Bearer');
}
public function getUser($token, UserProviderInterface $userProvider) : UserInterface
{
try {
$user = $this->jwtEncoder->decode($token);
} catch(Throwable $e) {
throw new AuthenticationException($e->getMessage());
}
return $userProvider->loadUserByUsername($user['email']);
}
public function checkCredentials($credentials, UserInterface $user) : bool
{
return true;
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
// on success, let the request continue
return null;
}
public function onAuthenticationFailure(Request $request, AuthenticationException $exception) : JsonResponse
{
$failure = [
'message' => $exception->getMessage()
];
return new JsonResponse($failure, Response::HTTP_UNAUTHORIZED);
}
/**
* Called when authentication is needed, but it's not sent
*/
public function start(Request $request, AuthenticationException $authException = null) : JsonResponse
{
$data = [
'message' => 'Authentication Required'
];
return new JsonResponse($data, Response::HTTP_UNAUTHORIZED);
}
public function supportsRememberMe() : bool
{
return false;
}
}
控制器
#[Route('/authentication_token', name: 'security_authentication_token', methods: ['POST'])]
public function createAuthenticationToken(
Request $request,
CreateTokenAuthenticationHandler $createTokenAuthenticationHandler,
ValidatorInterface $validator
): JsonResponse
{
$createTokenAuthentication = CreateTokenAuthentication::createFromPayload($request->request->all());
$errors = $validator->validate($createTokenAuthentication);
if (count($errors) > 0) {
foreach ($errors as $error) {
$message[]= sprintf("Field %s: %s ", $error->getPropertyPath(), $error->getMessage());
}
return new JsonResponse($message, JsonResponse::HTTP_BAD_REQUEST);
}
$token = $createTokenAuthenticationHandler->handle($createTokenAuthentication);
return new JsonResponse(['token' => $token], JsonResponse::HTTP_OK);
}
我生成令牌的处理程序
public function handle(CreateTokenAuthentication $createTokenAuthentication) : string
{
$user = $this->processAuthentication($createTokenAuthentication);
return $this->jwtEncoder->encode(
[
'email' => $user->getEmail(),
'role' => $user->getRoles()
]
);
}
谢谢。
我在带有令牌和到期日期的数据库中使用带有 symfony 路由的手动自定义刷新令牌。
目前我在 api 平台中创建带有自定义 symfony 控制器的 jwt 令牌,提供者并使用 JWTEncoderInterface 进行编码,使用来自外部 api 的身份验证。我的数据库中有用户但没有密码。如何使用该系统实现刷新令牌?
security.yml
providers:
# used to reload user from session & other features (e.g. switch_user)
user_provider:
id: App\Security\UserProvider
firewalls:
dev:
pattern: ^/_(profiler|wdt)
security: false
api:
pattern: ^/api/
stateless: true
anonymous: true
provider: user_provider
guard:
authenticators:
- app.authenticator
main:
anonymous: true
stateless: true
pattern: /authentication_token
我的验证器
<?php
namespace App\Security\Guard;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Guard\AbstractGuardAuthenticator;
use Lexik\Bundle\JWTAuthenticationBundle\Encoder\JWTEncoderInterface;
use Throwable;
class Authenticator extends AbstractGuardAuthenticator
{
private JWTEncoderInterface $jwtEncoder;
public function __construct(JWTEncoderInterface $jwtEncoder)
{
$this->jwtEncoder = $jwtEncoder;
}
/**
* Called on every request to decide if this authenticator should be
* used for the request. Returning `false` will cause this authenticator
* to be skipped.
*/
public function supports(Request $request) : bool
{
return $request->headers->has('Authorization Bearer');
}
/**
* Called on every request. Return whatever credentials you want to
* be passed to getUser() as $credentials.
*/
public function getCredentials(Request $request) : string
{
return $request->headers->get('Authorization Bearer');
}
public function getUser($token, UserProviderInterface $userProvider) : UserInterface
{
try {
$user = $this->jwtEncoder->decode($token);
} catch(Throwable $e) {
throw new AuthenticationException($e->getMessage());
}
return $userProvider->loadUserByUsername($user['email']);
}
public function checkCredentials($credentials, UserInterface $user) : bool
{
return true;
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
// on success, let the request continue
return null;
}
public function onAuthenticationFailure(Request $request, AuthenticationException $exception) : JsonResponse
{
$failure = [
'message' => $exception->getMessage()
];
return new JsonResponse($failure, Response::HTTP_UNAUTHORIZED);
}
/**
* Called when authentication is needed, but it's not sent
*/
public function start(Request $request, AuthenticationException $authException = null) : JsonResponse
{
$data = [
'message' => 'Authentication Required'
];
return new JsonResponse($data, Response::HTTP_UNAUTHORIZED);
}
public function supportsRememberMe() : bool
{
return false;
}
}
控制器
#[Route('/authentication_token', name: 'security_authentication_token', methods: ['POST'])]
public function createAuthenticationToken(
Request $request,
CreateTokenAuthenticationHandler $createTokenAuthenticationHandler,
ValidatorInterface $validator
): JsonResponse
{
$createTokenAuthentication = CreateTokenAuthentication::createFromPayload($request->request->all());
$errors = $validator->validate($createTokenAuthentication);
if (count($errors) > 0) {
foreach ($errors as $error) {
$message[]= sprintf("Field %s: %s ", $error->getPropertyPath(), $error->getMessage());
}
return new JsonResponse($message, JsonResponse::HTTP_BAD_REQUEST);
}
$token = $createTokenAuthenticationHandler->handle($createTokenAuthentication);
return new JsonResponse(['token' => $token], JsonResponse::HTTP_OK);
}
我生成令牌的处理程序
public function handle(CreateTokenAuthentication $createTokenAuthentication) : string
{
$user = $this->processAuthentication($createTokenAuthentication);
return $this->jwtEncoder->encode(
[
'email' => $user->getEmail(),
'role' => $user->getRoles()
]
);
}
谢谢。
我在带有令牌和到期日期的数据库中使用带有 symfony 路由的手动自定义刷新令牌。