Конфигурация безопасности Symfony, check_path идет к определенному контроллеру

Я новичок в symfony, и я пытаюсь создать свою собственную аутентификацию. (У меня есть внешняя система аутентификации, поэтому я объявил свой класс User и UserProvider) Я настроил некоторые маршруты, контроллеры и безопасность yml, но когда я отправляю форму входа, я получаю сообщение об ошибке

Для доступа к этому ресурсу требуется полная аутентификация.

Вот мой конфиг для безопасности:

security:
encoders:
    App\Domain\User\ValueObject\User: bcrypt
providers:
    UserProvider:
        id: App\Providers\UserProvider

firewalls:
    dev:
        pattern: ^/(_(profiler|wdt)|css|images|js)/
        security: false
    login:
        pattern: ^/login
        anonymous: ~
    login_others:
        pattern: ^/login/.*$
        anonymous: ~
    register:
        pattern: ^/register.*$
        anonymous: ~
    bye:
        pattern: ^/bye
        anonymous: ~
    main:
        provider: UserProvider
        pattern: ^/.*
        form_login:
            # submit the login form here
            check_path: user.login.check

            # the user is redirected here when they need to log in
            login_path: /login
        logout:
            path:   /logout
            target: /login
            invalidate_session: false

# Easy way to control access for large sections of your site
# Note: Only the *first* access control that matches will be used
access_control:
     - { path: ^/login$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
     - { path: ^/login/.*$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
     - { path: ^/register.*$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
     - { path: ^/bye$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
     - { path: ^/.+$, roles: ROLE_USER }

И мой контроллер для маршрутов выглядит так:

    class LoginController extends Controller
{
    /**
     * @param AuthenticationUtils $authUtils
     * @param TokenStorageInterface $tokenStorage
     * @return Response
     *
     * @Route("/login", name="user.login", methods="GET")
     */
    public function loginAction(
        AuthenticationUtils $authUtils,
        TokenStorageInterface $tokenStorage
    ) {
        if (!is_null($tokenStorage->getToken()) && in_array('ROLE_USER', $tokenStorage->getToken()->getRoles())) {
            return $this->redirect($this->generateUrl('dashboard'));
        }

        $error = $authUtils->getLastAuthenticationError();
        $lastUsername = $authUtils->getLastUsername();

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

    /**
     *
     * @Route("/login_check", name="user.login.check", methods={"POST"})
     */
    public function loginCheckAction()
    {

    }

Любая идея, что я делаю неправильно? Я почти уверен, что это проблема конфигурации, но, похоже, я этого не понимаю.


person Adrian Modliszewski    schedule 26.03.2018    source источник
comment
Если я добавлю дополнительный access_control для моего пути login_check следующим образом: - { path: ^/login_check$, roles: IS_AUTHENTICATED_ANONYMOUSLY }, я получу сообщение об ошибке Контроллер должен вернуть ответ (нуль задан).   -  person Adrian Modliszewski    schedule 26.03.2018
comment
Вы можете обновить свой вопрос с дополнительной информацией вместо использования комментариев. У вас что-нибудь заработало до того, как вы добавили все эти брандмауэры? Это может быть неочевидно, но каждый брандмауэр запускает довольно много классов. Я действительно не думаю, что они нужны. Можно попробовать начать с базовой конфигурации, заставить что-то работать, а затем, возможно, добавить кое-что. И если вам нужна какая-то пользовательская аутентификация, вероятно, вам нужен компонент Guard.   -  person Cerad    schedule 26.03.2018


Ответы (2)


Вот простая конфигурация:

#config/packages/security.yaml
# ...
providers:
    user_provider:
        entity:
            class: App\Providers\UserProvider
firewalls:    
    main:
        anonymous: ~
        form_login:
            login_path: login
            check_path: login
        logout:
            path: /logout
            target: /
access_control:
    - { path: dashboard, roles: ROLE_USER }

ЛогинКонтроллер

/**
 * @Route("/login", name="login")
 */
public function login(Request $request, AuthenticationUtils $authenticationUtils)
{
    $error = $authenticationUtils->getLastAuthenticationError();

    $lastUsername = $authenticationUtils->getLastUsername();

    return $this->render('login.html.twig', array(
        'last_username' => $lastUsername,
        'error'         => $error,
    ));
}

Затем вы можете просто настроить перенаправление по умолчанию после входа в систему:

#config/packages/security.yaml
security:
    # ...
    firewalls:
        main:
            form_login:
                # ...
                default_target_path: dashboard

Надеюсь это поможет

person Geo    schedule 28.03.2018

В конце концов я придумал немного более рабочую конфигурацию

security:
    encoders:
        App\Domain\User\ValueObject\User: bcrypt
    providers:
        UserProvider:
            id: App\Security\UserProvider

    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        main:
            anonymous: ~
            provider: UserProvider
            pattern: ^/.*
            form_login:
                login_path: user.login
            logout:
                path:   /logout
                target: user.login
                invalidate_session: false

    # Easy way to control access for large sections of your site
    # Note: Only the *first* access control that matches will be used
    access_control:
         - { path: ^/login.*$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
         - { path: ^/register.*$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
         - { path: ^/.+$, roles: ROLE_USER }

Как видите, я не настроил путь проверки для моего form_login. Это потому, что он не хотел заменять токен анонимного пользователя зарегистрированным, поэтому я в конечном итоге создал свою собственную конечную точку для проверки входа и сделал это вручную, что выглядит следующим образом:

/**
 * @param Request $request
 * @param PasswordAuthenticator $authenticator
 * @param UserProvider $provider
 * @param Session $session
 * @param TokenStorageInterface $storage
 * @return \Symfony\Component\HttpFoundation\RedirectResponse|Response
 *
 * @Route("/login/check", name="user.login.check", methods={"POST"})
 */
public function checkLoginUser(
    Request $request,
    PasswordAuthenticator $authenticator,
    UserProvider $provider,
    Session $session,
    TokenStorageInterface $storage
) {
    $token = $authenticator->createToken(
        $request,
        $request->request->get('_username'),
        $request->request->get('_password'),
        'UserProvider'
    );

    $authenticator->supportsToken($token, 'UserProvider');
    try {
        $newToken = $authenticator->authenticateToken($token, $provider, $token->getUser());

        $storage->setToken($newToken);
        $session->set('_security_main', serialize($newToken));

        return $this->redirect($this->generateUrl('dashboard'));
    } catch (CustomUserMessageAuthenticationException $e) {
        $error = $e->getMessage();
    }

    return $this->render('user/login.twig', [
        'error'         => $error,
        'last_username' => $request->request->get('_username'),
    ]);

}
person Adrian Modliszewski    schedule 10.04.2018