<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Symfony中文教程 &#187; Security</title>
	<atom:link href="http://www.newlifeclan.com/symfony/archives/category/cookbook/cookbook-2-6/security-cookbook-2-6/feed" rel="self" type="application/rss+xml" />
	<link>http://www.newlifeclan.com/symfony</link>
	<description>站在巨人肩膀上的phpweb框架</description>
	<lastBuildDate>Fri, 12 Dec 2025 00:58:27 +0000</lastBuildDate>
	<language>zh-CN</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.0.38</generator>
	<item>
		<title>(Security)在登录表单使用CSRF保护</title>
		<link>http://www.newlifeclan.com/symfony/archives/315</link>
		<comments>http://www.newlifeclan.com/symfony/archives/315#comments</comments>
		<pubDate>Thu, 26 Mar 2015 06:33:55 +0000</pubDate>
		<dc:creator><![CDATA[napoleon]]></dc:creator>
				<category><![CDATA[Cook 2.6]]></category>
		<category><![CDATA[Cookbook]]></category>
		<category><![CDATA[Security]]></category>

		<guid isPermaLink="false">http://www.newlifeclan.com/symfony/?p=315</guid>
		<description><![CDATA[<p>当使用登录表单时，你应该确保你的应用免受CSRF(跨站请求伪造)攻击。Security组件已经内置了对CSRF [&#8230;]</p>
<p><a rel="nofollow" href="http://www.newlifeclan.com/symfony/archives/315">(Security)在登录表单使用CSRF保护</a>，首发于<a rel="nofollow" href="http://www.newlifeclan.com/symfony">Symfony中文教程</a>。</p>
]]></description>
				<content:encoded><![CDATA[<p>当使用登录表单时，你应该确保你的应用免受CSRF(跨站请求伪造)攻击。Security组件已经内置了对CSRF的防御支持。在本文中，您将学习如何在登录表单使用它。<span id="more-315"></span></p>
<h2><b>配置CSRF保护</b></h2>
<p>首先，配置Security组件，它能够提供CSRF保护。这个Security组件需要一个 CSRF token provider。你可以把它设置为使用默认的表单组件。</p><pre class="crayon-plain-tag"># app/config/security.yml
security:
    firewalls:
        secured_area:
            # ...
            form_login:
                # ...
                csrf_provider: form.csrf_provider</pre><p>Security组件还可以进一步配置，但是login表单的CSRF的所有信息都在这里了。</p>
<p>&nbsp;</p>
<h2>渲染CSRF字段</h2>
<p>Security组件还需要检查CSRF token，你需要在login表单中添加一个CSRF token的hidden字段。默认情况下，这个字段的名称是 _csrf_token. 隐藏字段一定要包含CSRF token，这个值需要使用这个csrf_token 函数生成。那么当使用login表单时，一定要在这个函数中传人‘authenticate’，才能够最终生成登录的token id。</p><pre class="crayon-plain-tag">{# src/Acme/SecurityBundle/Resources/views/Security/login.html.twig #}

{# ... #}
&lt;form action="{{ path('login_check') }}" method="post"&gt;
    {# ... the login fields #}

    &lt;input type="hidden" name="_csrf_token"
        value="{{ csrf_token('authenticate') }}"
    &gt;

    &lt;button type="submit"&gt;login&lt;/button&gt;
&lt;/form&gt;</pre><p>在这之后，你就有能力保护你的表单免受CSRF攻击。</p>
<blockquote><p>你还能够在你的配置文件里改变你的csrf字段名称，你需要设置csrf_parameter。那么改变token id 需要设置intention：</p><pre class="crayon-plain-tag"># app/config/security.yml
security:
    firewalls:
        secured_area:
            # ...
            form_login:
                # ...
                csrf_parameter: _csrf_security_token
                intention: a_private_string</pre><p>&nbsp;</p></blockquote>
<p><a rel="nofollow" href="http://www.newlifeclan.com/symfony/archives/315">(Security)在登录表单使用CSRF保护</a>，首发于<a rel="nofollow" href="http://www.newlifeclan.com/symfony">Symfony中文教程</a>。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.newlifeclan.com/symfony/archives/315/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>(Security)如何去搭建一个传统的登录表单</title>
		<link>http://www.newlifeclan.com/symfony/archives/300</link>
		<comments>http://www.newlifeclan.com/symfony/archives/300#comments</comments>
		<pubDate>Tue, 24 Mar 2015 15:29:01 +0000</pubDate>
		<dc:creator><![CDATA[napoleon]]></dc:creator>
				<category><![CDATA[Cook 2.6]]></category>
		<category><![CDATA[Cookbook]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[登录表单]]></category>

		<guid isPermaLink="false">http://www.newlifeclan.com/symfony/?p=300</guid>
		<description><![CDATA[<p>注意：如果你需要为存储在某种数据库中的用户做一个登录表单，那么你应该考虑使用FOSUserBundle，这有助 [&#8230;]</p>
<p><a rel="nofollow" href="http://www.newlifeclan.com/symfony/archives/300">(Security)如何去搭建一个传统的登录表单</a>，首发于<a rel="nofollow" href="http://www.newlifeclan.com/symfony">Symfony中文教程</a>。</p>
]]></description>
				<content:encoded><![CDATA[<p>注意：如果你需要为存储在某种数据库中的用户做一个登录表单，那么你应该考虑使用FOSUserBundle，这有助于你建立你的User对象，还为您提供了常见的登录、注册、忘记密码的路由和控制器。</p>
<p><span id="more-300"></span></p>
<p>在此文章中，将构建一个传统的登录表单。当然，当用户登录时，你可以从数据库或者任何地方加载用户。</p>
<p>本章假设您已经遵循了security章节并且http_basic 认证正常工作。</p>
<p>首先，启用防火墙下表单登录</p><pre class="crayon-plain-tag"># app/config/security.yml
security:
    # ...

    firewalls:
        default:
            anonymous: ~
            http_basic: ~
            form_login:
                login_path: /login
                check_path: /login_check</pre><p></p>
<blockquote><p>这个login_path和check_path也可以是路由名称（但不能有强制通配符例如 /login/{foo}）这里foo没有默认值</p></blockquote>
<p>现在，当安全系统启动认证过程，它会让用户跳转到登录表单 /login。你的工作是实现这个登录表单视觉。首先，创建一个新的SecurityController在bundle中：</p><pre class="crayon-plain-tag">// src/AppBundle/Controller/SecurityController.php
namespace AppBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;

class SecurityController extends Controller
{
}</pre><p>下一步创建两个路由：分别是刚才form_login下的设置的两个路径（/login和/login_check）:</p>
<p>annotations</p><pre class="crayon-plain-tag">// src/AppBundle/Controller/SecurityController.php

// ...
use Symfony\Component\HttpFoundation\Request;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;

class SecurityController extends Controller
{
    /**
     * @Route("/login", name="login_route")
     */
    public function loginAction(Request $request)
    {
    }

    /**
     * @Route("/login_check", name="login_check")
     */
    public function loginCheckAction()
    {
        // this controller will not be executed,
        // as the route is handled by the Security system
    }
}</pre><p>&nbsp;</p>
<p>非常好！下一步，你要去添加loginAction的逻辑，并把需要的渲染到login表单：</p><pre class="crayon-plain-tag">// src/AppBundle/Controller/SecurityController.php

public function loginAction(Request $request)
{
    $authenticationUtils = $this-&gt;get('security.authentication_utils');

    // get the login error if there is one
    $error = $authenticationUtils-&gt;getLastAuthenticationError();

    // last username entered by the user
    $lastUsername = $authenticationUtils-&gt;getLastUsername();

    return $this-&gt;render(
        'security/login.html.twig',
        array(
            // last username entered by the user
            'last_username' =&gt; $lastUsername,
            'error'         =&gt; $error,
        )
    );
}</pre><p></p>
<blockquote><p> 这个security.authentication_utils服务和<tt class="docutils literal"><code><em><span style="text-decoration: underline"><span style="color: #ff0000"><a class="reference external" style="color: #ff0000;text-decoration: underline" title="Symfony\Component\Security\Http\Authentication\AuthenticationUtils" href="http://api.symfony.com/2.6/Symfony/Component/Security/Http/Authentication/AuthenticationUtils.html">AuthenticationUtils</a></span></span></em>类在symfony2.6都有介绍。</code></tt></p></blockquote>
<p>不要让这个控制器迷惑你。你看到当用户提交表单的这一刻，security系统会自动处理表单提交到这个控制器。如果用户提交了一个无效的用户名和密码，该控制器可以从security系统中读出表单提交的错误，以便把他显示给用户。</p>
<p>换句话说,你的工作是显示登录表单和任何可能发生的登录错误,但是security系统本身负责检查提交的用户名和密码并认证用户。</p>
<p>最后，创建模版：</p><pre class="crayon-plain-tag">{# app/Resources/views/security/login.html.twig #}
{# ... you will probably extends your base template, like base.html.twig #}

{% if error %}
    &lt;div&gt;{{ error.messageKey|trans(error.messageData) }}&lt;/div&gt;
{% endif %}

&lt;form action="{{ path('login_check') }}" method="post"&gt;
    &lt;label for="username"&gt;Username:&lt;/label&gt;
    &lt;input type="text" id="username" name="_username" value="{{ last_username }}" /&gt;

    &lt;label for="password"&gt;Password:&lt;/label&gt;
    &lt;input type="password" id="password" name="_password" /&gt;

    {#
        If you want to control the URL the user
        is redirected to on success (more details below)
        &lt;input type="hidden" name="_target_path" value="/account" /&gt;
    #}

    &lt;button type="submit"&gt;login&lt;/button&gt;
&lt;/form&gt;</pre><p></p>
<blockquote><p>这个传入到模版的错误变量是一个<span style="text-decoration: underline"><em><span style="color: #ff0000"><span class="goog-text-highlight" style="color: #ff0000"><a class="reference external" style="color: #ff0000" title="Symfony的\分量\安全\核心\异常\的AuthenticationException" href="http://api.symfony.com/2.6/Symfony/Component/Security/Core/Exception/AuthenticationException.html">AuthenticationException</a>。</span></span></em></span>它包含很多信息－一些敏感信息－关于认证失败信息，所以你要明智的使用它。</p></blockquote>
<p>要实现这些东西，要注意这几个要求：</p>
<ul>
<li>该表单必须提交到/login_check,因为你在security.yml的form_login健中配置的</li>
<li>这个用户名一定要name为_username并且password一定要name为_password。</li>
</ul>
<blockquote><p>其实所有的这些都可以配置到form_login健下，请查看 <em><span style="text-decoration: underline"><span style="color: #ff0000"><a style="color: #ff0000;text-decoration: underline" href="http://symfony.com/doc/current/reference/configuration/security.html#reference-security-firewall-form-login" target="_blank">form登录配置</a></span></span></em>。</p></blockquote>
<p>此登录表单目前没有使用CSRF攻击。如果需要请阅读<span style="color: #ff0000"> <a class="reference internal" style="color: #ff0000" href="http://symfony.com/doc/current/cookbook/security/csrf_in_login_form.html"><em>Using CSRF Protection in the Login Form</em></a> </span>。</p>
<p>就是这样！当您提交表单，security系统会自动检查用户的凭证，验证用户或向用户发送错误信息在登陆表单。</p>
<p>回顾整个过程：</p>
<p>1.用户试图访问被保护的资源。</p>
<p>2.防火期启用认证过程将用户重定向到登录表单（/login）</p>
<p>3.这个例子中，通过路由（route）和控制器（controller）来显示登录表单。</p>
<p>4.用户提交登录表单到 /login_check;</p>
<p>5.security系统截取请求，检查用户提交的凭据，验证他们是否正确，如果他不是系统允许的，页面会重新跳转到表单。</p>
<p>&nbsp;</p>
<h2>成功后，重定向</h2>
<p>如果提交的凭证是正确的，该用户会被重新定向到请求的原始页面（如/admin/foo）。如果用户最初直接进入登录页面，它需要跳转到首页。这些都是可以设定的，并且允许你指定到一个指定的url上。</p>
<p>更多细节，请参阅 <em><span style="text-decoration: underline"><span style="color: #ff0000"><a style="color: #ff0000;text-decoration: underline" href="http://symfony.com/doc/current/cookbook/security/form_login.html">How to Customize your Form Login</a></span></span></em>。</p>
<p>&nbsp;</p>
<h2>避免常见问错误</h2>
<p>在设置表单时应该注意一些常见的陷阱。</p>
<p><strong>1.创建正确的路由</strong></p>
<p>首先，确保你已经定义了正确的/login和/login_check，他们应该和你配置的login_path和check_path是一样的。如果你配置错误他会重定向到一个404页面，而不是登录页面，或者会出现提交表单不执行任何操作（你会一遍又一遍的看到登录表单）。</p>
<p><strong>2.确保登录页面可以访问</strong></p>
<p>此外，要确保登录页面匿名用户可以访问。例如，下面的配置-ROLE_ADMIN角色用于所有的URL（包括 /login），将会出现重定向循环：</p><pre class="crayon-plain-tag"># app/config/security.yml

# ...
access_control:
    - { path: ^/, roles: ROLE_ADMIN }</pre><p>添加access_control中添加一个 /login/*，并且指定一个任何身份都可以进入的角色。</p><pre class="crayon-plain-tag"># app/config/security.yml

# ...
access_control:
    - { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/, roles: ROLE_ADMIN }</pre><p>另外，如果您的防火墙没有允许匿名用户（没有<tt class="docutils literal"><code>anonymous</code></tt> 键），你需要去创建一个特殊的防火墙，允许匿名用户登录：</p><pre class="crayon-plain-tag"># app/config/security.yml

# ...
firewalls:
    # order matters! This must be before the ^/ firewall
    login_firewall:
        pattern:   ^/login$
        anonymous: ~
    secured_area:
        pattern:    ^/
        form_login: ~</pre><p><strong> 3.确保 /login_check 位于防火墙的后面</strong></p>
<p>确保你的check_path的url(如 /login_check)在表单登录防火墙里（例如本例，单一的防火墙匹配所有URL，包含/login_check）。如果/login_check不匹配路由，你会收到一个<span style="color: #339966">Unable to find the controller for path &#8220;/login_check&#8221;</span>的异常。</p>
<p>4.多个防火墙不共享相同的Security内容</p>
<p>如果你使用多个防火墙并且你进行认证了一个防火墙，其他的防火墙就不会对此做自动认证了。不同的防火墙，就像不同的安全系统。要做到这一点，你就必须要明确指定不同防火墙下相同的<span style="text-decoration: underline"><span style="color: #ff0000;text-decoration: underline"> <a class="reference internal" style="color: #ff0000;text-decoration: underline" href="http://symfony.com/doc/current/reference/configuration/security.html#reference-security-firewall-context"><em>Firewall Context</em></a>  </span></span>。但大多数应用，有一个主要的防火墙就足够了。</p>
<p>5.路由错误不受防火墙限制</p>
<p>Security已经把路由里的404页面设置成了不受防火墙限制。这意味着在这些页面上，你不能检测Security甚至访问用户对象。请查看 <span style="text-decoration: underline"><em><span style="color: #ff0000"><a style="color: #ff0000;text-decoration: underline" href="http://symfony.com/doc/current/cookbook/controller/error_pages.html" target="_blank">How to Customize Error Pages</a></span></em></span></p>
<p><a rel="nofollow" href="http://www.newlifeclan.com/symfony/archives/300">(Security)如何去搭建一个传统的登录表单</a>，首发于<a rel="nofollow" href="http://www.newlifeclan.com/symfony">Symfony中文教程</a>。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.newlifeclan.com/symfony/archives/300/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
