无需用户越来越ROLE_USER FOSUserbundle +附加HTTP认证 [英] FOSUserbundle + Additional HTTP auth without user getting ROLE_USER

查看:99
本文介绍了无需用户越来越ROLE_USER FOSUserbundle +附加HTTP认证的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我与Symfony2的安全系统中的小问题。这是我需要实现:

I have a "little" problem with the Symfony2 security system. This is what I need to achieve:


  • /需要一个HTTP认证之前的任何页面都可以看到。我要保护整个页面以恒定的用户名/密码对。用户输入正确的对后,他应该是一个来宾(而不是ROLE_USER)UND能够通过FOSUserBundle形式登录

  • / API通过HTTP需要一个单独的登录身份验证,独立于FOSU​​serBundle和其他HTTP认证

我已经成功地提供了API单独的登录。这是我的完整security.yml:

I already managed to provide a separate login for the API. This is my complete security.yml:

security:
    encoders:
        FOS\UserBundle\Model\UserInterface: sha512
        Symfony\Component\Security\Core\User\User: plaintext

    role_hierarchy:
        ROLE_ADMIN:       ROLE_USER
        ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]

    providers:
        in_memory_http:
            memory:
                users:
                    User1: { password: PW1, roles: ROLE_HTTP }
        in_memory_api:
            memory:
                users:
                    User2: { password: PW2, roles: ROLE_API }
        fos_userbundle:
            id: fos_user.user_provider.username_email

    firewalls:
        api:
            pattern: ^/api
            http_basic:
                provider: in_memory_api
                realm: "API login"

        http:
            pattern: ^/
            provider: in_memory_http
            http_basic:
                realm: "Hello"
            context: primary_auth            

        main:
            pattern: ^/                      
            form_login:                 
                provider: fos_userbundle    
                login_path: fos_user_security_login                            
                csrf_provider: form.csrf_provider
                check_path: fos_user_security_check
            logout: 
                path: fos_user_security_logout
                target: home         
            anonymous: true                   
            context: primary_auth        

        dev:
            pattern:  ^/(_(profiler|wdt)|css|images|js)/
            security: false

        login:
            security: false

        secured_area: 
            anonymous: ~

    access_control:
        - { path: ^/api, roles: ROLE_API }
        - { path: ^/user/login.html, roles: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/user/logout.html, roles: IS_AUTHENTICATED_REMEMBERED }

本作品近百如预期,但遗憾的是没有完全...
在/ API部分的工作方式类似,我想它的工作。无事可做在这里,我希望。

This works nearly as expected, but unfortunately not completely... The /api part works like I wanted it to work. Nothing to do here, I hope.

但是,当我浏览到/,进入用户1 / PW1和发送的凭据,我可以访问的页面,就像预期。唯一的问题是,用户1被登录!但我想用户1不能像一个正常的用户操作。他应该只需要使用普通的登录表单和其余/除/ API的。我甚至不能注销该用户。如果我浏览到/user/login.html而user1的登录(由于所需的HTTP验证),并输入一个真实的fosuserbundle用户的有效的用户数据,我得到:你必须配置检查路径被防火墙处理使用form_login在安全的防火墙配置。

But when I navigate to /, enter User1/PW1 and send the credentials, I get access to the page, just like expected. The only problem is that the User1 gets logged in! But I want User1 not to be handled like a normal user. He should just be required to access the normal login form and the rest of / except of /api. I can't even log out this user. If I navigate to /user/login.html while User1 is logged in (due to the required http auth) and enter valid user data of a real fosuserbundle user, I get: "You must configure the check path to be handled by the firewall using form_login in your security firewall configuration."

如果我要退出,我得到:你必须激活您的安全防火墙配置注销。

If I want to log out, I get: "You must activate the logout in your security firewall configuration."

我要的是怎样的一个两步验证。
首先HTTP认证,那么FOSUserBundle形式。

What I want is kind of a two step authentication. First HTTP Auth, then the FOSUserBundle form.

有人可以帮我吗? :)该文档是不是很好在这一点上...

Can somebody help me? :) The documentation is not very good at this point...

推荐答案

所以.....

几个小时的纯疼痛后,我放弃了与Symfony2的安全组件尝试它。我也没能实现我想要的东西与Apache(尝试SetEnvIf之后和FilesMatch)。

After several hours of pure pain I gave up on trying it with the Symfony2 Security Component. I also did not manage to realize what I want with Apache (Tried SetEnvIf and FilesMatch).

所以我写了一个请求监听器我想要做什么。如果有人有同样的问题,这里是我的解决方案!

So I wrote a request listener that does what I want. If anybody has the same problem, here is my solution!

use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpFoundation\Response;

class RequestListener
{
    /**
    * Returns true iff the specified $password belongs to the $user and the $user has access to the specified $area
    */
    private function hasAccess($user, $password, $area) {
        $users = array("User1" => array("password" => "PW1", 
                                             "areas" => array("portal")),
                       "User2" => array("password" => "PW2", 
                                                     "areas" => array("API", "portal"))
                 );

        return $user
            && array_key_exists($user, $users)
            && $users[$user]["password"] == $password
            && in_array($area, $users[$user]["areas"]);
    }

    /**
    * Extracts the area out of the $path
    */
    public function getArea($path) {
        if (substr($path, 0, 4) == "/api") {
            return "API";    
        } else {
            return "portal";
        }
    }

    /**
    * Service handler
    */
    public function onKernelRequest(GetResponseEvent $event) {      
        $request = $event->getRequest();    

        # $path cointains the path to the virtual resource the user requested!
        # If the user calls app_dev.php/api/users, then $path is "/api/users"
        # If the user calls app.php/api/users,     then $path is "/api/users"
        # If the user calls /api/users,            then $path is "/api/users"
        # If the user calls /app_dev.php,          then $path is "/"
        # If the user calls /,                     then $path is "/"
        # and so on
        #
        # ==> $path abstracts the front controller away
        $path = $request->getPathInfo();
        $area = $this->getArea($path);

        # $user, $password are null if no AUTH data is sent
        $user = $request->server->get("PHP_AUTH_USER");
        $password = $request->server->get("PHP_AUTH_PW");   

        # If the user has no access, he must log in as another user
        if (!$this->hasAccess($user, $password, $area)) {   
            # In case the response already exists (in most cases not) we use it and modify it
            $response = $event->hasResponse() ? $event->getResponse() : new Response();             
            $response->setStatusCode(Response::HTTP_UNAUTHORIZED); # Code 401
            $response->headers->set("WWW-Authenticate", "Basic realm=\"".$area."\"");   
            $response->setContent("Please provide valid data");         
            $response->send();
            die(); # To make sure the page is not shown!
        }   
    }
}

现在一切似乎工作...

Now everything seems to work...

这篇关于无需用户越来越ROLE_USER FOSUserbundle +附加HTTP认证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆