繁体   English   中英

Symfony守护程序:access_control无效

[英]Symfony guard : access_control has no effect

我是symfony的新手,我正在尝试获取基于JWT的基本防护验证器。 这项工作主要来自此处的文章,这里我删除了所有用户检查(目前): http : //kolabdigital.com/lab-time/symfony-json-web-tokens-authentication-guard

我认为我无法获得某些东西,因为我无法使其正常运行。 更准确地说,它适用于任何地方,即使在我设置的例外情况下也是如此。

这是Check服务,与文章基本相同,没有用户管理,并且有一些日志记录:

<?php

namespace AppBundle\Security;

use Lexik\Bundle\JWTAuthenticationBundle\Encoder\DefaultEncoder;
use Lexik\Bundle\JWTAuthenticationBundle\TokenExtractor\AuthorizationHeaderTokenExtractor;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Guard\AbstractGuardAuthenticator;
use Psr\Log\LoggerInterface;

class TokenAuthenticator extends AbstractGuardAuthenticator
{
    private $jwtEncoder;
    private $logger;

    public function __construct(DefaultEncoder $jwtEncoder, LoggerInterface $logger)
    {
        $this->logger = $logger;
        $this->jwtEncoder = $jwtEncoder;
    }

    public function start(Request $request, AuthenticationException $authException = null)
    {
        $route = $request->attributes->get('_route');
        $url = $request->getUri();
        $this->logger->info($route . ' : ' . $url);
        return new JsonResponse('Authentication required', 401);
    }

    public function getCredentials(Request $request)
    {

        if(!$request->headers->has('Authorization')) {
            return;
        }

        $extractor = new AuthorizationHeaderTokenExtractor(
            'Bearer',
            'Authorization'
        );

        $token = $extractor->extract($request);

        if(!$token) {
            return;
        }

        return $token;
    }

    public function getUser($credentials, UserProviderInterface $userProvider)
    {
        $data = $this->jwtEncoder->decode($credentials);

        if(!$data){
            return;
        }

        $username = $data['username'];

        // TODO get user from user collection
        $user = ['username' => $username];

        // Is user is encoded in token and exists, then it's fine
        if(!$user){
            return;
        }

        return $user;
    }


    public function checkCredentials($credentials, UserInterface $user)
    {
        return true;
    }

    public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
    {
        return new JsonResponse([
            'message' => $exception->getMessage()
        ], 401);
    }

    public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
    {
        return;
    }

    public function supportsRememberMe()
    {
        return false;
    }

}

而security.yml(不包括所有内容)只是为了检查行为。

# To get started with security, check out the documentation:
# http://symfony.com/doc/current/security.html
security:

    # http://symfony.com/doc/current/security.html#b-configuring-how-users-are-loaded
    providers:
        in_memory:
            memory: ~

    firewalls:
        # disables authentication for assets and the profiler, adapt it according to your needs
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false

#################################
# Secured section
#

        # Custom authentication firewall for all request thats starts from /api
        api:
            pattern: ^/api
            guard:
                authenticators:
                    - app.token_authenticator


#################################
# Main Configuration
#

        main:
            anonymous: ~
            # activate different ways to authenticate

            # http_basic: ~
            # http://symfony.com/doc/current/security.html#a-configuring-how-your-users-will-authenticate

            # form_login: ~
            # http://symfony.com/doc/current/cookbook/security/form_login_setup.html



    access_control:
        #- { path: ^/auth, roles: IS_AUTHENTICATED_ANONYMOUSLY }
        #- { path: ^/version, roles: IS_AUTHENTICATED_ANONYMOUSLY }
        #- { path: ^/api, roles: [ROLE_USER, ROLE_API_USER] }
        - { path: ^/api, roles: IS_AUTHENTICATED_ANONYMOUSLY }

        #- { path: ^/(css|js), roles: IS_AUTHENTICATED_ANONYMOUSLY }
        #- { path: ^/(_wdt|_profiler), roles: IS_AUTHENTICATED_ANONYMOUSLY }
        #- { path: ^/, roles: ROLE_USER }

我只是在^ / api上放置了防护,并在同一路径上放置了一个control_access来允许匿名。 我希望在具有该配置的任何路径上都不会调用保护服务,但是每次都会调用它。 我想我对它的工作方式缺少一些了解。 我的理解是:

  • 首先检查访问控制
  • 如果有匹配的行,它将接受(第一个)
  • 如果设置了IS_AUTHENTICATED_ANONYMOUSLY,则不检查防火墙
  • 否则,下一个检查是防火墙配置,它告诉您使用TokenAuthenticator进行检查

最初的目的是锁定/ api ,但/ api / auth/ api / version除外,后者无需控制即可访问。

感谢您的帮助,我认为经过1天半的时间,我无法对此进行思考。

作为记录,我设法解决此问题。

首先,Guard Authenticator建立在真实的用户存储库上,这不是我们想要的。 我们希望使用Redis进行快速检查,并在Mongo中使用UserRepository。 此外,我们不需要PHP会话,我们需要无状态系统(仅活动令牌位于redis中)。

因此,我要做的是为Guard Authenticator创建一个虚拟User对象,实现所需的接口。

在访问时,我们通过在Redis中获取其令牌以及其他数据来检查用户是否已经知道。 这些附加数据包括所需的User对象。

在连接上,我们实际上检查数据库中的用户,如果还可以,我们创建虚拟User对象,并使用令牌将其压入redis。

使用该系统,一切都很好。 这不是最漂亮的解决方案,但是它允许在可能有多个实例的无状态环境中使用Guard。

您好,我最近遇到了同样的问题。 当我们具有带有acces_control的自定义防护身份验证器时,缺少关于此用例的完善文档。

首先:

我的理解是:

  • 首先检查访问控制

不,这句话是失败的,因此,它使您对其余的内容有所了解。

如您在此处看到的那样,FIREWALL(您的令牌身份验证器保护器)的工作是启动身份验证过程,这是系统要做的第一件事-检查给定的凭据(如果有)是否会生成经过身份验证的令牌。

如果确定,则系统将执行其第二项工作即授权 -例如,由于使用access_control的角色不足,可能拒绝对某些资源的访问。

知道了所有这些之后,您就可以将您的保护令牌身份验证器视为某种形式(我知道这不是真实的东西,而只是为了进行清晰的解释)登录表单机制的抽象虚拟变量,仅在您登录时运行点击您的登录路径。 唯一的区别是,当您遇到某个登录路径时,防护将不会运行,而是在请求具有Authorization标头时运行(并且可以完全自定义,就像您在getCredentials函数中定义的那样)

顺便说一句,在最新的symfony中, 有一个新的支持功能 ,该功能在getCredentials之前调用,您应该在其中检查请求是否具有足够的标头以启动Authentication(或所需的任何检查)。

因此,基本上您说: “当请求具有授权标头时,请谨慎对待” ,无论您请求哪个uri。 可能是因为您以这种方式发送了基本身份验证凭据-您的请求(即使是api / version,尤其是api / auth)也具有此标头。 然后,会先触发您的警卫,再导致您描述的行为。

作为一种可能的解决方案-在警卫人员内部,您可以将其设置为在请求具有X-AUTH-TOKEN标头时触发(因此,可以将不同的标头用于公共访问路径,而将不同的标头用于私有)。 这样,您对api / version的调用将不会触发防护,甚至对api / auth的调用也不会触发防护,因为您将使用Authorization标头而不是X-AUTH-TOKEN标头发送凭据。

如果是这样,您的防护将不会被触发, 然后使用已确定的未经身份验证的令牌来触发THEN ,您将访问访问控件 ,该控件将决定是否允许您进行资源分配(该路径的IS_AUTHENTICATED_ANONYMOUSLY是)。

我希望我向您解释了一下。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM