1

我有一个自定义 symfony 安全登录的问题,灵感来自 Symfony 食谱的教程“如何构建传统登录表单”。一切正常,直到我从 /login 路由登录。然后我想要重定向到的每条路线都会导致无限循环。也许我错过了什么?

//security.yml 安全性:

encoders:
        AppBundle\Entity\User:
            algorithm: bcrypt

providers:
    mysql:
        entity:
            class: AppBundle:User
            property: username


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

    main:
        anonymous: ~
        form_login:
            login_path: login
            check_path: login_check
        logout:
            path: logout


access_control:
    - { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/, roles: IS_AUTHENTICATED_FULLY }

//路由.yml

index:
path: /
defaults: { _controller: AppBundle:Main:main }
app:
    resource: "@AppBundle/Controller/"
    type:     annotation

//SecurityController.php

<?php

namespace AppBundle\Controller;

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

class SecurityController extends Controller
{
/**
 * @Route("/login", name="login")
 */
public function loginAction() {
    $authenticationUtils = $this->get("security.authentication_utils");

    $error = $authenticationUtils->getLastAuthenticationError();
    $name = $authenticationUtils->getLastUsername();

    return $this->render(
        ':security:login.html.twig',
        ["name" => $name, "error" => $error]
    );
}
/**
 * @Route("/login_check", name="login_check")
 */
public function loginCheckAction() {
}
/**
 * @Route("/logout",name="logout")
 */
public function logoutAction() {
}

}

//login.twig.html

{% if error %}
<div>{{ error.messageKey|trans(error.messageData, 'security') }}</div>
{% endif %}

<form action="{{ path('login_check') }}" method="post">
     <label for="username">Username:</label>
     <input type="text" id="username" name="_username" value="{{ name }}" />

     <label for="password">Password:</label>
     <input type="password" id="password" name="_password" />
     <input type="hidden" name="_target_path" value="/" />

     <button type="submit">login</button>
</form>
4

5 回答 5

3

好的,所以我终于找到了问题,问题根本不在路线或安全性上。我只是在用户实体中序列化错误。调试器中没有提到一些拼写错误的 symfony。奇怪的是它导致了这种行为。无论如何,感谢任何试图帮助我的人。

于 2016-03-28T18:11:29.253 回答
0

@qooplmao我不明白你为什么说“引荐来源..这是登录页面”引荐来源是“/”女巫不是登录页面(“/login”)而是mainController中某处的路由。如果 /login 路由在 / 之前匹配,可以吗?

较早的路线总是赢,那么 routing.yml 可能是

login:
    resource: "@AppBundle/Controller/SecurityController.php"
    type:     annotation
app:
    resource: "@AppBundle/Controller/"
    type:     annotation
index:
    path: /
    defaults: { _controller: AppBundle:Main:main }

如果您在主控制器中使用注释,您也可以删除索引。

于 2016-03-28T11:06:53.693 回答
0

原因是登录脚本正在将您转发到登录页面,当它看到您已登录时,它会将您转发到引荐来源......这是登录页面......等等......

要解决这个问题,您有几个选择。

1)您可以在您的中设置默认目标路径,app/config/security.yml以便每次用户登录时都会将它们转发到特定路由。这种方法的问题在于,使用always_use_default_target_path将意味着它永远不会进入引荐页面,但是如果您不使用它并且尝试登录失败,它将引导您进入登录页面(引荐来源网址在此观点)。

firewalls:
    //..
    main:
        anonymous: ~
        form_login:
            default_target_path: **default_route**
            always_use_default_target_path: true
            login_path: login
            check_path: login_check
        logout:
            path: logout

2)您可以在表单登录中设置一个字段,该字段设置默认目标路径,根据情况可以是引用者或指定的路径。这种方法的问题是用户需要通过登录过程才能被转发,因此如果用户出于某种原因返回登录页面,他们将需要在被重定向之前再次登录。

//...

{% set referer = app.request.headers.get('referer') %}
{% set targetPath = referer is not null and referer != url('login')
    ? referer
    : path('**default_route**')
%}

<form action="{{ path('login_check') }}" method="post">
    //...

    <input type="hidden" name="_target_path" value="{{ targetPath }}" />
</form>

3)我的建议您可以在您的登录控制器中设置一个检查,以检查用户是否已经登录,然后将用户重定向到特定路线。这样做的好处是它会阻止已经登录的用户进入登录表单,但仍然可以让您在可能的情况下将用户转发到引用页面/路线。

/**
 * @Route("/login", name="login")
 */
public function loginAction() {
    if (null !== $this->getUser()) {
        return new RedirectResponse($this->generateUrl('**default_route**'));
    }

    //...
}
于 2016-03-28T10:34:48.477 回答
0

你应该改变

access_control:
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }

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

让 login_check 在防火墙后面。

您的 routing.yml 对我来说似乎很奇怪,您可以发布您的控制器和您的树枝来查看您的路线吗?

于 2016-03-28T04:05:28.223 回答
0

试试这样:security.yml 安全性:

encoders:
        AppBundle\Entity\User:
            algorithm: bcrypt

providers:
    mysql:
        entity:
            class: AppBundle:User
            property: username


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

    main:
        anonymous: ~
        form_login:
            login_path: login
            check_path: login_check
        logout:
            path: logout


access_control:
    - { path: ^/login$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/, roles: IS_AUTHENTICATED_FULLY }

路由.yml

login:
    resource: "@AppBundle/Controller/SecurityController.php"
    type:     annotation
app:
    resource: "@AppBundle/Controller/"
    type:     annotation

安全控制器.php

<?php

namespace AppBundle\Controller;

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

class SecurityController extends Controller
{
/**
 * @Route("/login", name="login")
 */
public function loginAction() {
    $authenticationUtils = $this->get("security.authentication_utils");

    $error = $authenticationUtils->getLastAuthenticationError();
    $name = $authenticationUtils->getLastUsername();

    return $this->render(
        ':security:login.html.twig',
        ["name" => $name, "error" => $error]
    );
}
/**
 * @Route("/login_check", name="login_check")
 */
public function loginCheckAction() {
}
/**
 * @Route("/logout",name="logout")
 */
public function logoutAction() {
}

}

登录.twig.html

{% if error %}
<div>{{ error.messageKey|trans(error.messageData, 'security') }}</div>
{% endif %}

<form action="{{ path('login_check') }}" method="post">
     <label for="username">Username:</label>
     <input type="text" id="username" name="_username" value="{{ name }}" />

     <label for="password">Password:</label>
     <input type="password" id="password" name="_password" />
     <input type="hidden" name="_target_path" value="{{ path('THE_NAME_OF_THE_ROUTE_YOU_WANT_TO_GO') }}" />

     <button type="submit">login</button>
</form>

在您的 mainController 中需要使用注释路由,如果它是您想要去的路由,则将例如 'THE_NAME_OF_THE_ROUTE_YOU_WANT_TO_GO' 替换为 '/page'...

这里有一些帮助:http: //symfony.com/doc/current/book/routing.html

于 2016-03-28T12:24:41.417 回答