Symfony 4.4 Auth0 如何从应用程序中完全注销用户

Posted

技术标签:

【中文标题】Symfony 4.4 Auth0 如何从应用程序中完全注销用户【英文标题】:Symfony 4.4 Auth0 how to completely logout user from the application 【发布时间】:2021-10-21 20:54:28 【问题描述】:

基本信息:

我创建了一个测试应用程序来测试 SSO(单点登录)是否有效。我使用 Auth0 作为 SSO 提供者。 Symfony 4.4 作为应用程序框架。我使用来自 Auth0 的 this 文章来创建基础知识。到目前为止,我可以登录/注销。

问题:

当我登录一次(使用凭据),然后注销然后再次登录时,我立即使用我之前使用的相同帐户登录。无需再次填写凭据。它似乎记住了会话或以某种方式没有完全注销用户。我希望用户在注销后必须使用凭据再次登录。由于我的一些用户将使用一台计算机进行应用程序(因此需要切换用户)。

可能的修复/额外信息:

根据那里的文档/社区,我应该看看this。但这似乎意味着我需要 API 调用来添加?federated。设置示例不使用哪个(可能是库为我做的)。此外,由make:auth(或make:user)生成的SecurityController 中的注销功能也不再执行代码。即使我更改了函数名称,它仍然让我退出。直到我删除/更改它停止的路线名称。这可能很糟糕,但如果我在注销时有机会执行 API 调用,我可以执行此 API 调用。

我能想到的最好的事情是更改 symfony 中的一些设置或添加一些小段代码以使其正确注销。但我不知道怎么做。

我的代码:

SecurityController.php

<?php

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;

class SecurityController extends AbstractController

    /**
     * @Route("/login", name="app_login")
     */
    public function login(AuthenticationUtils $authenticationUtils): Response
    
        // get the login error if there is one
        $error = $authenticationUtils->getLastAuthenticationError();

        // last username entered by the user
        $lastUsername = $authenticationUtils->getLastUsername();

        return $this->render('security/login.html.twig', ['last_username' => $lastUsername, 'error' => $error]);
    

    /**
     * @Route("/logout", name="app_logout")
     */
    public function logout()
    
        // Does not trigger at all. It does not stop the page but just continues to redirect and logout.
        dump($this->get('session'));
        dump($session);
        dump("test");
        exit();
        throw new \Exception('This method can be blank - it will be intercepted by the logout key on your firewall');
    

Auth0ResourceOwner.php

<?php

namespace App;

use HWI\Bundle\OAuthBundle\OAuth\ResourceOwner\GenericOAuth2ResourceOwner;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolver;

class Auth0ResourceOwner extends GenericOAuth2ResourceOwner

    protected $paths = array(
        'identifier' => 'user_id',
        'nickname' => 'nickname',
        'realname' => 'name',
        'email' => 'email',
        'profilepicture' => 'picture',
    );

    public function getAuthorizationUrl($redirectUri, array $extraParameters = array())
    
        return parent::getAuthorizationUrl($redirectUri, array_merge(array(
            'audience' => $this->options['audience'],
        ), $extraParameters));
    

    protected function configureOptions(OptionsResolver $resolver)
    
        parent::configureOptions($resolver);

        $resolver->setDefaults(array(
            'authorization_url' => 'base_url/authorize',
            'access_token_url' => 'base_url/oauth/token',
            'infos_url' => 'base_url/userinfo',
            'audience' => 'base_url/userinfo',
        ));

        $resolver->setRequired(array(
            'base_url',
        ));

        $normalizer = function (Options $options, $value) 
            return str_replace('base_url', $options['base_url'], $value);
        ;

        $resolver->setNormalizer('authorization_url', $normalizer);
        $resolver->setNormalizer('access_token_url', $normalizer);
        $resolver->setNormalizer('infos_url', $normalizer);
        $resolver->setNormalizer('audience', $normalizer);
    

routes.yaml

hwi_oauth_redirect:
  resource: "@HWIOAuthBundle/Resources/config/routing/redirect.xml"
  prefix: /connect

hwi_oauth_connect:
  resource: "@HWIOAuthBundle/Resources/config/routing/connect.xml"
  prefix: /connect

hwi_oauth_login:
  resource: "@HWIOAuthBundle/Resources/config/routing/login.xml"
  prefix: /login

auth0_login:
  path: /auth0/callback

auth0_logout:
  path: /auth0/logout
  # controller: App/Controller/SecurityController::logout

hwi_oauth.yaml

hwi_oauth:
  firewall_names: [main]
  # https://github.com/hwi/HWIOAuthBundle/blob/master/Resources/doc/2-configuring_resource_owners.md
  resource_owners:
    auth0:
      type: oauth2
      class: 'App\Auth0ResourceOwner'
      client_id: "%env(AUTH0_CLIENT_ID)%"
      client_secret: "%env(AUTH0_CLIENT_SECRET)%"
      base_url: "https://%env(AUTH0_DOMAIN)%"
      scope: "openid profile email"

security.yaml

security:
    encoders:
        App\Entity\Users:
            algorithm: auto

    # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
    providers:
        # used to reload user from session & other features (e.g. switch_user)
        app_user_provider:
            entity:
                class: App\Entity\Users
                property: username
        oauth_hwi:
            id: hwi_oauth.user.provider
        # used to reload user from session & other features (e.g. switch_user)
    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        main:
            anonymous: ~
            provider: oauth_hwi
            oauth:
                resource_owners:
                    auth0: "/auth0/callback"
                login_path: /login
                failure_path: /login
                default_target_path: /testPage
                oauth_user_provider:
                    service: hwi_oauth.user.provider
            guard:
                authenticators:
                    - App\Security\LoginFormAuthenticator
            logout:
                path: /logout
                # target: /login

    access_control:
        -  path: ^/login$, roles: IS_AUTHENTICATED_ANONYMOUSLY 

        # Everyone that logged in can go to /
        -  path: '^/testPage', roles: [IS_AUTHENTICATED_FULLY] 

.env

AUTH0_CLIENT_ID=not-so-secret-but-secret
AUTH0_CLIENT_SECRET=secret
AUTH0_DOMAIN=dev-...

用户转储:

TestPageController.php on line 17:
HWI\Bundle\OAuthBundle\Security\Core\User\OAuthUser #3742 ▼
  #username: "testUser"

我希望这是可以理解的。任何帮助表示赞赏。

【问题讨论】:

【参考方案1】:

您似乎必须从您正在使用的 oauth 服务中注销,这里是 similar issue。

在代码中解决:

src/Security/CustomLogoutSuccessHandler.php

<?php

namespace App\Security;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Security\Http\Logout\LogoutSuccessHandlerInterface;

class CustomLogoutSuccessHandler implements LogoutSuccessHandlerInterface

    private $target;

    public function __construct(string $target)
    
        $this->target = $target;
    

    public function onLogoutSuccess(Request $request)
    
        return new RedirectResponse($this->target);
    

security.yaml

logout:
   path: /logout
   success_handler: App\Security\CustomLogoutSuccessHandler

services.yaml

services:
   App\Security\CustomLogoutSuccessHandler:
       arguments: ['%env(resolve:LOGOUT_TARGET_URL)%']

.env

LOGOUT_TARGET_URL=https://yourAuth0AppDomain.auth0.com/v2/logout?returnTo=yourRedirectURL&client_id=secret

使用 Github 问题中的代码会将您重定向 4 次。注销->Route->(.env)Auth0->Route.

使用上面显示的代码会将您重定向 3 次。注销->Auth0->路由。只是一个小小的改进。

Code from this post.

【讨论】:

哎呀……我的错!我会将 security.yaml 添加到我的问题中。顺便说一句,我确实注册了注销。 感谢添加,能否尝试将/logout替换为app_logout,这指的是您的控制器的注销功能(尝试前不要忘记删除转储并退出) 嗯,奇怪。我手动将这些东西更改为 /logout 和转储只是为了尝试。但现在我照你说的做,因此把它们移回去。现在我似乎在注销函数中得到了错误/抛出异常代码。当然,消息是:This method can be blank - it will be intercepted by the logout key on your firewall. 我现在仍然登录。它以前没有这样做,我不知道现在和以前有什么不同:P。那么现在该怎么办呢?看来我的注销不再被防火墙拦截了。 嗯,看来您必须从正在使用的 oauth 服务中注销,这里是 similar issue 嘿@gdus,你的链接解决了我的问题!非常感谢。注销过程似乎仍然有点双重,但至少它有效。也许您可以将答案更改为问题中的答案。然后我会接受答案,也许会对其进行一些编辑以使其更清楚。由于 github 的答案是可以理解的,但没有很好的记录。

以上是关于Symfony 4.4 Auth0 如何从应用程序中完全注销用户的主要内容,如果未能解决你的问题,请参考以下文章

Symfony 4.4如何使用collectionType从0个字段开始

如何在 Symfony 中访问已登录的 Auth0 用户的电子邮件地址?

从 Symfony 3.4 迁移到 Symfony 4.4 后,自定义投票器无法按预期工作

从 symfony 4.4 中截取 login_check 路径

为啥升级到 Symfony 4.4 后我不再看到错误预览页面?

无效的凭据消息登录 Symfony 4.4