我正在任何 Symfony2 项目中实现一个简单的认证区域。
没什么难的,即使我可以使用 FOSUserBundle,我也不使用,但这不是问题,我的问题实际上是针对安全方案和防火墙。
基本流程:
- 定义需要具有足够角色的经过身份验证的用户配置文件的防火墙
- 创建允许用户进行身份验证的登录表单页面
- 管理错误,并在防火墙内重定向经过身份验证的用户
我可以很容易地用 SF2 做到这一点。
但是,我需要这个项目有点不同的东西:
防火墙不需要任何经过身份验证的配置文件。
它仅在找到经过身份验证的配置文件时才显示附加信息,但应该可以匿名访问。
所以我会把一个给定的页面作为登录表单页面和一个经典的防火墙页面
更多信息在这里:
- 我有一个主页,显示公共信息
- 登录表单是此主页的一部分,顺便说一下图形需求(下拉菜单)
- 如果任何用户使用表单登录,我不想将其重定向到定义的防火墙页面,但允许经过身份验证的用户留在此主页上并显示其他信息
其实登录表单页面===防火墙主页===公共主页;
问题是在这个页面上,用户永远不会被认为是经过身份验证的,即使在使用表单登录后,但可以访问所有私人 ^/members 页面。
# Security.yml
firewalls:
home:
pattern: ^/$
anonymous: ~
members_area:
pattern: ^/
provider: <any_working_entity-based_provider>
form_login:
login_path: /
check_path: /login_check
post_only: true
default_target_path: /
use_referer: false
logout:
path: /logout
target: /
invalidate_session: false
access_control:
- { path: ^/, roles: IS_AUTHENTICATED_ANONYMOUSLY } # Public page, login page AND firewall page
- { path: ^/members, roles: ROLE_USER } # Other firewall pages
# My/Super/Bundle/Resources/views/home.html.twig
# [...]
{% if app.user %}
// This part is never displayed, even when the user is successfully authenticated
<h3>Welcome home {{ app.user.username }}</h3>
{% else %}
// This part is always shown...
<form action='{{ path('MySuperBundle_members_login_check') }}' method='post'>
<div>
<label for='_username'>Username</label>
<input type='text' id='_username' name='_username' value='{{ last_username }}' />
</div>
<div>
<label for='_password'>Password</label>
<input type='text' id='_password' name='_password' value='{{ last_username }}' />
</div>
[... CSRF ...]
<div>
<input type='submit' name='submit' value='Submit' />
</div>
</form>
{% endif %}
所以最后:
- 主页 (/) 可匿名访问:OK
- 会员区 (^/members) 需要任何经过身份验证的个人资料:OK
- 主页始终显示登录表单,即使用户已经登录(twig test {% if app.user %} 始终仅在主页上返回 false)