【问题标题】:Logout from http_basic auth in Symfony2从 Symfony2 中的 http_basic auth 注销
【发布时间】:2015-05-27 13:06:21
【问题描述】:

每当我转到 /admin/logout 时,我都会正确地重定向到我的项目的根目录,但在我访问 /admin/ 时仍然登录,因为没有提示我输入凭据。

这是我的配置:

security.yml

security:
    firewalls:
        admin_area:
            pattern:    ^/admin
            http_basic: ~
            stateless:  true
            switch_user: { role: ROLE_SUPER_ADMIN, parameter: _want_to_be_this_user }
            logout: { path: /admin/logout, target: / }

AdminBundle/Resources/config/routing.yml

logout:
    pattern:   /logout

app/config/routing.yml

admin:
    resource: "@AdminBundle/Resources/config/routing.yml"
    prefix:   /admin

授权仍然存在,因为标头状态为 Authorization:Basic YWRtaW46cEAkJHcwUmQh,所以我猜在请求期间仍会向应用程序提供凭据。

我知道没有像this question 那样从HTTP Basic Auth 注销的正确方法,但也许 Symfony2 允许这样做?

【问题讨论】:

  • 尝试将您的注销模式更改为/admin/logout,这样它就在防火墙下,您也可以检查您是否没有检查过remember me - 尝试删除cookie然后登录并注销
  • 感谢@Vardius 的评论,但我的模式已经 /admin/logout 正确重定向。另外,我还没有实现选项remember_me(还)。
  • 在您的帖子中,我可以看到您的routing.yml 中的注销不在防火墙下。尝试更改它,然后在 security.yml 中尝试使用路由名称而不是模式 logout: path: logout....
  • 实际上,我的路由routing.yml 文件位于AdminBundle 捆绑包下,它的路由在app/config/routing.yml 中导入,就像admin: resource: "@AdminBundle/Resources/config/routing.yml" prefix: /admin 一样,所以路由的模式是/admin/logout,所以在防火墙。不幸的是,更改security.yml 中路径名称的模式没有任何效果(仍然登录)。感谢您的帮助。

标签: php security symfony basic-authentication logout


【解决方案1】:

一旦通过 http auth 登录,您的浏览器将缓存并以如下标头的形式将您的登录凭据添加到每个后续请求中:

Authorization:Basic YWRtaW46YWRtaW4=

当您注销时,对服务器的下一个请求仍将保留您的 http 凭据并再次登录。

所以诀窍是在服务器端销毁会话后丢失客户端的 http 凭据。

过去有一些骇人听闻的方法,例如提交虚假凭据或一些模糊的 IE 方法来删​​除缓存。但我认为这些方法仍然行不通。

什么仍然有效(我用 symfony 2.7 和 google chrome 45 测试了以下方法)是用 HTTP 401 未经授权的响应回复客户端。

检查一下:

将以下内容添加到 app/config/security.yml 文件中的注销部分

logout:
    success_handler: logout_listener

到你的服务配置 app/config/services.yml

logout_listener:
    class: AppBundle\LogoutListener

然后创建一个响应 HTTP 401 未授权的侦听器

<?php 

namespace AppBundle;

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

class LogoutListener implements  LogoutSuccessHandlerInterface 
{
    public function onLogoutSuccess(Request $request) 
    {
        return new Response('', 401);
    }
}

注销后,您的应用会向浏览器发送 401,浏览器会认为身份验证失败,导致身份验证缓存被清除(谁想记住错误的凭据)并再次提示您输入凭据

【讨论】:

  • 但是,跳转到http://logout@www.yourdomain.com/your/page 确实有效(即尝试使用 URL 中的假凭据登录)。不知道为什么这会清除缓存的身份验证,但简单的 401 响应却没有,但你去吧。
  • 刚刚在 Chromium 56 上尝试了“logout@”技巧,它不起作用
【解决方案2】:

@Niki Van Cleemput 的答案似乎并不适用于所有情况。当我测试它时,它在 Chrome 44 上可以,但在 Firefox 48 上不行。 这是一个受HTTP authentication logout via PHP启发的解决方案:

安全参数:

security:
    # ... your encoders, role_hierarchy, providers...
    firewalls:
        dev:
            pattern:  ^/(_(profiler|wdt)|css|images|js)/
            security: false

        main:
            pattern: ^/
            anonymous: ~
            stateless:  true
            http_basic:
                realm: "My admin area"
            # no logout parameter as it is handled manually

    access_control:
        - { path: ^/admin, roles: ROLE_ADMIN }

具有“假”注销操作的控制器:

<?php

namespace Me\Bundle\CoreBundle\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;

/**
 * Security stuff.
 */
class SecurityController extends Controller
{
    /**
     * Logout confirmation.
     *
     * @Route("/logout", name="logout")
     */
    public function logoutAction()
    {
        return $this->render('@EasyAdmin/default/logout.html.twig'); // change with your template path
    }
}

在您的布局中:

<script type="text/javascript">
    function logout() {
        var xmlhttp;
        if (window.XMLHttpRequest) {
            xmlhttp = new XMLHttpRequest();
        }
        // code for IE
        else if (window.ActiveXObject) {
            xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
        }
        if (window.ActiveXObject) {
            // IE clear HTTP Authentication
            document.execCommand("ClearAuthenticationCache");
            window.location.href='{{ path('logout') }}';
        } else {
            xmlhttp.open("GET", '{{ path('easyadmin') }}', true, "logout", "logout");
            xmlhttp.send("");
            xmlhttp.onreadystatechange = function() {
                if (xmlhttp.readyState == 4) {window.location.href='{{ path('logout') }}';}
            }
        }

        return false;
    }
</script>

添加注销链接:

<a href="#" onclick="logout()"><i class="hidden-xs fa fa-user"></i> Logout</a>

至少它适用于 Chrome 和 Firefox,如果它在其他浏览器上不起作用,请告诉我。

【讨论】:

  • 这看起来很糟糕......将用户退回到http://logout@www.yourdomain.com/your/page(其中'logout'是一个无效的用户名)更好更干净。这应该会导致身份验证失败并清除相关缓存。
  • 我同意,很讨厌。但对我来说,这是唯一适用于所有浏览器且无需调用“假”用户注销的解决方案。
  • 恕我直言,调用假用户强制注销可能比所有这些代码更好/更干净(您只需要一个注销链接)。
猜你喜欢
  • 2012-09-26
  • 2021-07-30
  • 2012-02-01
  • 2017-10-31
  • 2011-08-24
  • 2012-09-17
  • 1970-01-01
  • 2021-09-03
相关资源
最近更新 更多