Symfony2:允许匿名访问所有不匹配的路由

时间:2015-03-13 14:06:27

标签: angularjs symfony symfony-security

我将Symfony2应用程序分为2个捆绑包:API为BackendBundle,AngularJS为"客户端"为FrontendBundle。一切都在防火墙下工作。

BackendBundle有实体,处理API路由; FrontendBundle具有Angular视图,路由等,并且只有一个带通配符的控制器:

class AngularController extends Controller {
    /**
     * @Route("/{route}", name="angular_index_all_unmatched_routes", requirements={"route" = ".*"})
     * @Template("FrontendBundle::index.html.twig")
     */
    public function angularIndexAction($route) {
        return ['route' => $route];
    }
}

FrontendBundle路由被定义为app/config/routing.yml中的最后一个资源,仅当任何其他路由未匹配时才会被调用。多亏了它,它可以处理Angular HTML5模式路由,如果它们可以直接访问(例如复制粘贴) - 并且它可以正常工作。

我想要做的是,定义防火墙和/或访问控制,以便匿名用户可以访问所有这些不匹配的路由(由AngularController::angularIndexAction()处理)。

为什么?我想打开一些API路由(通过前端代理)以供非用户访问(例如通过电子邮件发送的确认网址,并向用户发送一些消息)。

我不想为每个匿名的用户编码访问控制列表" Angular"路线,我想只为API路线做。最后,那些不匹配的路由应该打开Angular的索引,该索引应该知道用户是否已登录(用于显示完整或简化的布局)并且应该处理Angular路由并显示某种类型的"访问被拒绝"请求失败的消息(有Symfony监听器和Angular的$provide拦截器)。

有什么建议吗?


编辑@Security上的AngularController::angularIndexAction()注释不起作用,它仍会重定向到防火墙入口点。


Edit2 :这是security.yml

的片段
firewalls:
    unsecured:
        pattern: ^/(_(profiler|wdt)|css|images|js)/
        security: false
        anonymous: true

    secured:
        pattern: '^.*$'
        form_login:
            login_path: /our-provider/login
            check_path: /our-provider/callback/
        anonymous: true
        entry_point: our_provider.entry_point

access_control:
    - { path: '^/our-provider/(login(/[a-zA-Z]+)?|logout|redirect|callback)', roles: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: '^/', roles: ROLE_USER }

我知道如果用户没有登录,{ path: '^/', roles: ROLE_USER }会将所有路由重定向到登录页面。我认为它显而易见并且没有提到它。我想要的是强制ROLE_USER用于匹配的路由,让IS_AUTHENTICATED_ANONYMOUSLY用于那些无法匹配的路由,而不是明确定义每个前端" proxy-route"。在我的情况下,没有404 Symfony页面,因为一切都进入angular_index_all_unmatched_routes路由,并且Angular路由定义决定是否有事情需要处理。

1 个答案:

答案 0 :(得分:0)

我没有尝试过,我无法在security.yml中开始猜测您现有的安全/路由设置,但我想您可以使用IS_AUTHENTICATED_ANONYMOUSLY将该方法列入白名单。来自Symfony docs

  

所有用户(甚至是匿名用户)都有此功能 - 这在将URL列入白名单以保证访问权限时非常有用 - 某些详细信息位于How Does the Security access_control Work?

因此,例如,如果您使用@Security注释,则可以执行类似(未测试)的操作:

class AngularController extends Controller {
    /**
     * @Route("/{route}", name="route", requirements={"route" = ".*"})
     * @Template("FrontendBundle::index.html.twig")
     * @Security("has_role('IS_AUTHENTICATED_ANONYMOUSLY')")
     */
    public function angularIndexAction($route) {
        return ['route' => $route];
    }
}

有关@Security注释here的更多信息。

希望这会有所帮助:)

修改

所有这一切,当你在access_control security.yml下定义/限制你的路线时,匹配过程在第一场比赛时停止。我假设您有一些角色限制路径,您应该明确定义 - 并将它们放在第一位,这样如果它们与流程停止匹配。

否则,您应该能够添加由角色IS_AUTHENTICATED_ANONYMOUSLY强制执行的全能路由。由于路由的路径定义是正则表达式,因此^/之类的内容应该捕获未明确定义的任何内容。只需确保限制路径定义之后将其放置。

在这种情况下,您不需要@Security注释。

修改2

我尝试使用干净的实例和HTTP BasicAuth来模拟这个,但我想要实现的是以下内容,我理解这与您的用例类似:

  • 创建一个包含路由//api/的后端控制器并触发HTTP BasicAuth身份验证弹出窗口
  • 创建一个路径/{route}的前端控制器,该控制器将匹配其他所有内容并进行匿名身份验证。

我的firewallaccess_control配置如下所示:

security:
    encoders:
        # encoder config here
    providers:
        # provider config here
firewalls:
    dev:
        pattern:  ^/(_(profiler|wdt)|css|images|js)/
        security: false
    secured:
        anonymous: ~
        http_basic: ~

access_control:
    - { path: ^/$,    roles: ROLE_USER }
    - { path: ^/api/, roles: ROLE_USER }
    - { path: ^/,     roles: IS_AUTHENTICATED_ANONYMOUSLY }

访问控制路径是正则表达式,因此^/$^/不一样。前者只与路线/完全匹配。后者将匹配以/开头的任何路线;例如:/home/products/contact等。

实际上,后者将匹配并匿名验证/api,但它不会与/api//api/1等匹配,因为这些已明确定义并限制为ROLE_USER

因此,一般的想法是明确地和(如果可能的话)与您想要限制的路线完全匹配,并首先声明这些路线。最后一个声明^/应该公开抓住任何其他路线。