Symfony5使用SelfValidatingPassport实现无用户ApiKey认证疑问
Symfony无用户体系下使用SelfValidatingPassport实现API Token校验方案
你当前代码直接进入
onAuthenticationFailure的核心原因是:UserBadge默认会调用系统配置的用户提供器尝试加载用户,你没有配置适配token校验的用户加载逻辑,用户加载失败直接触发认证失败流程。
SelfValidatingPassport本身不需要额外的凭据校验步骤,只要其携带的所有Badge校验通过,即可完成认证。你不需要依赖数据库用户体系,只需要补充两个部分的实现:1. 极简的虚拟用户类 2. 自定义token校验逻辑的用户加载流程。
方案1:直接在UserBadge中传入自定义加载回调(最简方案)
该方案不需要额外创建UserProvider类,适合简单校验场景。
- 首先创建极简虚拟用户类,实现
UserInterface接口:
// src/Security/DummyApiUser.php namespace App\Security; use Symfony\Component\Security\Core\User\UserInterface; class DummyApiUser implements UserInterface { public function __construct(private string $token) {} // 按需返回角色,比如API访问默认角色 public function getRoles(): array { return ['ROLE_API']; } // 无密码场景返回空即可 public function getPassword(): ?string { return null; } // 无盐场景返回空即可 public function getSalt(): ?string { return null; } // 可以返回token作为用户标识 public function getUserIdentifier(): string { return $this->token; } public function eraseCredentials() {} }
- 修改你的
authenticate方法,在UserBadge中传入自定义加载回调,直接编写token校验逻辑:
public function authenticate(Request $request): PassportInterface { $apiToken = $request->headers->get('X-AUTH-TOKEN'); if (null === $apiToken) { throw new CustomUserMessageAuthenticationException('No API token provided'); } return new SelfValidatingPassport( new UserBadge($apiToken, function (string $token) { // 在这里写你的token校验逻辑,比如: // 1. 校验token是否在你预设的合法token列表中 // 2. 校验token的签名是否有效、是否过期等 $validTokens = ['your_valid_token_1', 'your_valid_token_2']; // 可替换为从配置/Redis中读取 if (!in_array($token, $validTokens)) { throw new CustomUserMessageAuthenticationException('Invalid API token'); } // 校验通过返回虚拟用户即可 return new DummyApiUser($token); }) ); }
方案2:自定义UserProvider实现(适合复用场景)
如果你有多处认证逻辑需要用到相同的token校验,可以创建自定义UserProvider统一维护校验规则:
- 创建UserProvider类:
// src/Security/ApiTokenUserProvider.php namespace App\Security; use Symfony\Component\Security\Core\Exception\UserNotFoundException; use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Core\User\UserProviderInterface; class ApiTokenUserProvider implements UserProviderInterface { public function loadUserByIdentifier(string $identifier): UserInterface { // $identifier就是传入的token $validTokens = ['your_valid_token_1', 'your_valid_token_2']; if (!in_array($identifier, $validTokens)) { throw new UserNotFoundException(); } return new DummyApiUser($identifier); } public function refreshUser(UserInterface $user): UserInterface { return $user; } public function supportsClass(string $class): bool { return DummyApiUser::class === $class; } }
- 在
config/packages/security.yaml中配置该用户提供器:
security: providers: api_token_provider: id: App\Security\ApiTokenUserProvider firewalls: api: pattern: ^/api provider: api_token_provider # 其余你的防火墙配置保持不变
- 你的原有
authenticate方法不需要修改,UserBadge会自动调用该Provider完成token校验和用户加载。
内容的提问来源于stack exchange,提问作者connectedMind
相关产品推荐
相关产品推荐

