Symfony 6中如何通过EveOnline SSO实现本地客户端认证
解决Symfony 6中EveOnline SSO登录后本地认证状态未设置的问题
核心结论
是的,你需要构建自定义认证器。Symfony 6的安全组件依赖认证器管理用户认证状态,你用的是第三方OAuth2登录(非表单密码模式),默认认证器完全不适用,必须自定义适配EveOnline SSO的认证逻辑。
分步实现方案
1. 创建自定义认证器类
新建src/Security/EveOnlineAuthenticator.php,继承Symfony提供的AbstractAuthenticator(减少重复代码),实现核心认证逻辑:
namespace App\Security; use App\Entity\User; use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Core\Exception\UserNotFoundException; use Symfony\Component\Security\Core\User\UserProviderInterface; use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator; use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge; use Symfony\Component\Security\Http\Authenticator\Passport\Passport; use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport; class EveOnlineAuthenticator extends AbstractAuthenticator { public function __construct( private EntityManagerInterface $em, private UrlGeneratorInterface $urlGenerator ) {} // 判断当前请求是否需要该认证器处理 public function supports(Request $request): ?bool { // 检查会话是否有Eve的token,且请求路径是需要认证的会员区 return $request->getSession()->has('token') && str_starts_with($request->getPathInfo(), '/member'); } // 执行认证逻辑 public function authenticate(Request $request): Passport { $token = $request->getSession()->get('token'); // 从Eve返回的token中获取角色ID(需和你User实体存储的字段对应) $characterId = $token->getResourceOwner()->getId(); return new SelfValidatingPassport( new UserBadge($characterId, function ($userIdentifier) { // 根据角色ID查找本地用户 $user = $this->em->getRepository(User::class)->findOneBy(['eveCharacterId' => $userIdentifier]); if (!$user) { throw new UserNotFoundException(); } return $user; }) ); } // 认证成功后的处理(直接放行即可) public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response { return null; } // 认证失败后的处理(跳回Eve登录页) public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response { $request->getSession()->remove('token'); return new RedirectResponse($this->urlGenerator->generate('eve_login')); } }
2. 配置Security.yaml
修改config/packages/security.yaml,把自定义认证器绑定到防火墙,并配置用户提供者:
security: enable_authenticator_manager: true password_hashers: App\Entity\User: algorithm: auto # 配置用户提供者:根据Eve角色ID查找本地用户 providers: app_user_provider: entity: class: App\Entity\User property: eveCharacterId firewalls: dev: pattern: ^/(_(profiler|wdt)|css|images|js)/ security: false main: lazy: true provider: app_user_provider # 绑定自定义认证器 custom_authenticators: - App\Security\EveOnlineAuthenticator logout: path: app_logout invalidate_session: true access_control: # 会员区需要ROLE_USER权限(需在User实体的getRoles()中返回) - { path: ^/member, roles: ROLE_USER }
3. 回调控制器补充会话设置
在你的SecurityController回调方法中,获取Eve的token并完成用户存储/更新后,把token存入会话,然后跳转到会员区:
// 回调方法示例 public function callback(Request $request, ClientRegistry $clientRegistry) { $client = $clientRegistry->getClient('eveonline'); $token = $client->getAccessToken('authorization_code', [ 'code' => $request->query->get('code') ]); // 保存/更新本地User实体逻辑... // 将Eve的token存入会话,供认证器读取 $request->getSession()->set('token', $token); // 跳转到会员区,此时认证器会自动触发认证 return $this->redirectToRoute('member_area'); }
4. 确保User实体符合要求
你的User实体必须实现Symfony\Component\Security\Core\User\UserInterface,关键方法示例:
public function getUserIdentifier(): string { // 返回Eve角色ID作为用户标识 return (string) $this->eveCharacterId; } public function getRoles(): array { // 至少返回ROLE_USER,否则无法访问会员区 return ['ROLE_USER']; }
内容的提问来源于stack exchange,提问作者L.H.
相关产品推荐
相关产品推荐

