You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Symfony 6中LexikJWTAuthenticationBundle按用户ID/用户名删Token并强制登出

在Symfony 6中处理LexikJWT Token失效与登录重定向

一、通过用户ID/用户名使LexikJWT Token失效

LexikJWTAuthenticationBundle本身是无状态设计,Token签发后服务端默认不存储,因此无法直接删除指定用户的Token。要实现通过用户ID或用户名让该用户所有Token失效,需搭建Token黑名单机制,具体步骤如下:

1. 选择存储方案

可选用Redis或数据库存储失效用户/Token信息:

  • Redis:用jwt_blacklist:{user_id}作为键,存储Token过期时间或Token列表,适合高性能场景。
  • 数据库:创建JwtBlacklist实体,包含userId、expiresAt(失效截止时间)等字段。

2. 拦截Token验证流程

自定义Token验证器,在每次请求时检查用户是否被拉黑:

// src/Security/Validator/BlacklistedUserValidator.php
namespace App\Security\Validator;

use Lexik\Bundle\JWTAuthenticationBundle\Encoder\JWTEncoderInterface;
use Lexik\Bundle\JWTAuthenticationBundle\TokenExtractor\TokenExtractorInterface;
use Symfony\Component\HttpFoundation\Request;
use Doctrine\ORM\EntityManagerInterface;

class BlacklistedUserValidator
{
    public function __construct(
        private TokenExtractorInterface $tokenExtractor,
        private JWTEncoderInterface $jwtEncoder,
        private EntityManagerInterface $em
    ) {}

    public function isUserBlacklisted(Request $request): bool
    {
        $token = $this->tokenExtractor->extract($request);
        if (!$token) {
            return false;
        }

        $payload = $this->jwtEncoder->decode($token);
        $userId = $payload['id'];

        // 检查用户是否在黑名单中
        $blacklistedEntry = $this->em->getRepository(JwtBlacklist::class)->findOneBy(['userId' => $userId]);
        return $blacklistedEntry !== null && $blacklistedEntry->getExpiresAt() > new \DateTime();
    }
}

3. 实现拉黑用户的方法

编写服务类,支持通过用户ID或用户名拉黑用户:

// src/Service/JwtBlacklistService.php
namespace App\Service;

use Doctrine\ORM\EntityManagerInterface;
use App\Entity\User;
use App\Entity\JwtBlacklist;

class JwtBlacklistService
{
    public function __construct(private EntityManagerInterface $em) {}

    public function blacklistUserById(int $userId): void
    {
        $blacklistEntry = new JwtBlacklist();
        $blacklistEntry->setUserId($userId);
        // 设置为Token最大有效期,确保所有未过期Token失效
        $blacklistEntry->setExpiresAt(new \DateTime('+1 day'));

        $this->em->persist($blacklistEntry);
        $this->em->flush();
    }

    public function blacklistUserByUsername(string $username): void
    {
        $user = $this->em->getRepository(User::class)->findOneBy(['username' => $username]);
        if ($user) {
            $this->blacklistUserById($user->getId());
        }
    }
}

4. 集成到安全验证流程

监听lexik_jwt_authentication.on_jwt_decoded事件,在Token解码后检查用户是否被拉黑,若拉黑则抛出异常终止请求:

// src/EventListener/JwtDecodedListener.php
namespace App\EventListener;

use App\Security\Validator\BlacklistedUserValidator;
use Lexik\Bundle\JWTAuthenticationBundle\Event\JWTDecodedEvent;
use Symfony\Component\Security\Core\Exception\AuthenticationException;

class JwtDecodedListener
{
    public function __construct(private BlacklistedUserValidator $validator) {}

    public function onJWTDecoded(JWTDecodedEvent $event): void
    {
        $request = $event->getRequest();
        if ($this->validator->isUserBlacklisted($request)) {
            throw new AuthenticationException('Your account has been logged out.');
        }
    }
}

二、登录状态下自动重定向至登出页面

结合黑名单机制,当用户持有有效Token但已被拉黑时,在请求处理阶段触发重定向:

1. 创建请求监听事件

监听kernel.request事件,检查用户状态并跳转:

// src/EventListener/BlacklistedUserRedirectListener.php
namespace App\EventListener;

use App\Security\Validator\BlacklistedUserValidator;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;

class BlacklistedUserRedirectListener
{
    public function __construct(
        private BlacklistedUserValidator $validator,
        private UrlGeneratorInterface $urlGenerator
    ) {}

    public function onKernelRequest(RequestEvent $event): void
    {
        if (!$event->isMainRequest()) {
            return;
        }

        $request = $event->getRequest();
        // 排除登出路由,避免循环跳转
        if ($request->attributes->get('_route') === 'app_logout') {
            return;
        }

        if ($this->validator->isUserBlacklisted($request)) {
            $response = new RedirectResponse($this->urlGenerator->generate('app_logout'));
            $event->setResponse($response);
        }
    }
}

2. 配置登出路由与安全规则

在routes.yaml定义登出路由:

app_logout:
    path: /logout

在security.yaml配置登出处理:

security:
    firewalls:
        main:
            logout:
                path: app_logout
                target: /login # 登出后跳转至登录页

内容的提问来源于stack exchange,提问作者echalh adil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 22:20:33