支付宝扫一扫付款
微信扫一扫付款
(微信为保护隐私,不显示你的昵称)
security系统是Symfony框架最为强力的部分之一,且可利用其配置文件进行很大程度上的控制。
下面是安全系统的全部默认配置。其中的每一部分都将在后面小节中进行解释。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 | # app/config/security.yml
security:
access_denied_url: ~ # Example: /foo/error403
# strategy can be: none, migrate, invalidate
# 策略可以是:none, migrate, invalidate
session_fixation_strategy: migrate
hide_user_not_found: true
always_authenticate_before_granting: false
erase_credentials: true
access_decision_manager:
strategy: affirmative # One of affirmative, consensus, unanimous
allow_if_all_abstain: false
allow_if_equal_granted_denied: true
acl:
# any name configured in doctrine.dbal section
# 可以是在doctrine.dbal区块中进行了配置的任何名字
connection: ~
cache:
id: ~
prefix: sf2_acl_
provider: ~
tables:
class: acl_classes
entry: acl_entries
object_identity: acl_object_identities
object_identity_ancestors: acl_object_identity_ancestors
security_identity: acl_security_identities
voter:
allow_if_object_identity_unavailable: true
encoders:
# Examples/使用样例:
Acme\DemoBundle\Entity\User1: sha512
Acme\DemoBundle\Entity\User2:
algorithm: sha512
encode_as_base64: true
iterations: 5000
# PBKDF2 encoder
# see the note about PBKDF2 below for details on security and speed
# 参考下面的PBKDF2相关注释以了解“安全性和速度”的细节
Acme\Your\Class\Name:
algorithm: pbkdf2
hash_algorithm: sha512
encode_as_base64: true
iterations: 1000
key_length: 40
# Example options/values for what a custom encoder might look like
# 关于自定义加密器的“键/值”配置样例:
Acme\DemoBundle\Entity\User3:
id: my.encoder.id
# BCrypt encoder
# see the note about bcrypt below for details on specific dependencies
# 参考下面的bcrypt相关注释以了解“特定依赖”的细节
Acme\DemoBundle\Entity\User4:
algorithm: bcrypt
cost: 13
# Plaintext encoder
# it does not do any encoding 它并不进行任何加密动作
Acme\DemoBundle\Entity\User5:
algorithm: plaintext
ignore_case: false
providers: # Required / 必选项
# Examples:
my_in_memory_provider:
memory:
users:
foo:
password: foo
roles: ROLE_USER
bar:
password: bar
roles: [ROLE_USER, ROLE_ADMIN]
my_entity_provider:
entity:
class: SecurityBundle:User
property: username
# name of a non-default entity manager
manager_name: ~
my_ldap_provider:
ldap:
service: ~
base_dn: ~
search_dn: ~
search_password: ~
default_roles: 'ROLE_USER'
uid_key: 'sAMAccountName'
filter: '({uid_key}={username})'
# Example custom provider 自定义user provider的使用样例
my_some_custom_provider:
id: ~
# Chain some providers / user provider的链式用法(译注:很重要)
my_chain_provider:
chain:
providers: [ my_in_memory_provider, my_entity_provider ]
firewalls: # Required / 必选项
# Examples:
somename:
pattern: .*
# restrict the firewall to a specific host
# 限制防火墙运行在指定host之下
host: admin\.example\.com
# restrict the firewall to specific http methods
# 限制防火墙运行在指定的http方法之下
methods: [GET, POST]
request_matcher: some.service.id
access_denied_url: /foo/error403
access_denied_handler: some.service.id
entry_point: some.service.id
provider: some_key_from_above
# manages where each firewall stores session information
# 管理每个防火墙存储session信息时的位置
# See "Firewall Context" below for more details
# 参考下面的“防火墙上下文”来了解细节
context: context_key
stateless: false
x509:
provider: some_key_from_above
remote_user:
provider: some_key_from_above
http_basic:
provider: some_key_from_above
http_basic_ldap:
provider: some_key_from_above
service: ldap
dn_string: '{username}'
http_digest:
provider: some_key_from_above
guard:
# A key from the "providers" section of your security config, in case your user provider is different than the firewall
# 这个键来自于你的安全配置中的“providers”区块,如果你的user provider与防火墙中的并不相同的话
provider: ~
# A service id (of one of your authenticators) whose start() method should be called when an anonymous user hits a page that requires authentication
# 一个服务定义id(你的某个authenticator),其start()方法应该在anonymous用户命中“一个需要认证”的页面后被调用
entry_point: null
# An array of service ids for all of your "authenticators"
# 一个由“你的所有authenticator之服务定义id”所组成的数组
authenticators: []
form_login:
# submit the login form here / 在这里提交表单登录
check_path: /login_check
# the user is redirected here when they need to log in
# 当用户需要登录时,将其跳转到这里
login_path: /login
# if true, forward the user to the login form instead of redirecting
# 若为true,将用户推送到登录表单而不是重定向(译注:forward是Symfony路由功能之一)
use_forward: false
# login success redirecting options (read further below)
# 登录成功后的跳转选项(下文有解释)
always_use_default_target_path: false
default_target_path: /
target_path_parameter: _target_path
use_referer: false
# login failure redirecting options (read further below)
# 登录失败后的跳转选项(下文有解释)
failure_path: /foo
failure_forward: false
failure_path_parameter: _failure_path
failure_handler: some.service.id
success_handler: some.service.id
# field names for the username and password fields
# 用户名和密码两个字段的表单变量名
username_parameter: _username
password_parameter: _password
# csrf token options / csrf token选项
csrf_parameter: _csrf_token
csrf_token_id: authenticate
csrf_token_generator: my.csrf_token_generator.id
# by default, the login form *must* be a POST, not a GET
# 默认时,登录表单 *必须* 是POST方式,不能是GET
post_only: true
remember_me: false
# by default, a session must exist before submitting an authentication request
# if false, then Request::hasPreviousSession is not called during authentication
# 默认是,session必须在提前一个authentication请求之前已经存在
# 否则的话,Request::hasPreviousSession在认证过程中将不被调用
require_previous_session: true
form_login_ldap:
# submit the login form here / 在这里提交表单登录
check_path: /login_check
# the user is redirected here when they need to log in
# 当用户需要登录时,将其跳转到这里
login_path: /login
# if true, forward the user to the login form instead of redirecting
# 若为true,将用户推送到登录表单而不是重定向(译注:forward是Symfony路由功能之一)
use_forward: false
# login success redirecting options (read further below)
# 登录成功后的跳转选项(下文有解释)
always_use_default_target_path: false
default_target_path: /
target_path_parameter: _target_path
use_referer: false
# login failure redirecting options (read further below)
# 登录失败后的跳转选项(下文有解释)
failure_path: /foo
failure_forward: false
failure_path_parameter: _failure_path
failure_handler: some.service.id
success_handler: some.service.id
# field names for the username and password fields
# 填写用户名和密码两个字段的表单变量名
username_parameter: _username
password_parameter: _password
# csrf token options / csrf token选项
csrf_parameter: _csrf_token
csrf_token_id: authenticate
csrf_token_generator: my.csrf_token_generator.id
# by default, the login form *must* be a POST, not a GET
# 默认时,登录表单 *必须* 是POST方式,不能是GET
post_only: true
remember_me: false
# by default, a session must exist before submitting an authentication request
# if false, then Request::hasPreviousSession is not called during authentication
# new in Symfony 2.3
# 默认是,session必须在提前一个authentication请求之前已经存在
# 否则的话,Request::hasPreviousSession在认证过程中将不被调用
# 这是Symofny 2.3的新功能
require_previous_session: true
service: ~
dn_string: '{username}'
remember_me:
token_provider: name
secret: "%secret%"
name: NameOfTheCookie
lifetime: 3600 # in seconds
path: /foo
domain: somedomain.foo
secure: false
httponly: true
always_remember_me: false
remember_me_parameter: _remember_me
logout:
path: /logout
target: /
invalidate_session: false
delete_cookies:
a: { path: null, domain: null }
b: { path: null, domain: null }
handlers: [some.service.id, another.service.id]
success_handler: some.service.id
anonymous: ~
# Default values and options for any firewall
# 任意防火墙的默认选项(键)和选项值
some_firewall_listener:
pattern: ~
security: true
request_matcher: ~
access_denied_url: ~
access_denied_handler: ~
entry_point: ~
provider: ~
stateless: false
context: ~
logout:
csrf_parameter: _csrf_token
csrf_token_generator: ~
csrf_token_id: logout
path: /logout
target: /
success_handler: ~
invalidate_session: true
delete_cookies:
# Prototype
name:
path: ~
domain: ~
handlers: []
anonymous:
secret: "%secret%"
switch_user:
provider: ~
parameter: _switch_user
role: ROLE_ALLOWED_TO_SWITCH
access_control:
requires_channel: ~
# use the urldecoded format 使用 urldecoded反加密格式路径
path: ~ # Example: ^/path to resource/
host: ~
ips: []
methods: []
roles: []
role_hierarchy:
ROLE_ADMIN: [ROLE_ORGANIZER, ROLE_USER]
ROLE_SUPERADMIN: [ROLE_ADMIN] |
当使用form_login
这个位于防火墙下面(firewall键之下)的authentication listener(认证监听器)时,有几个常规选项,用来配置“表单登录”的体验。
更多细节,参考如何配置你的表单登陆一文。
值类型:string
默认值:/login
这是用户在尝试访问一个受保护的资源但却没有被“完全认证(fully authenticated)”时,应该被重定向到某处的路由或路径(除非use_forward
被设为true
)。
此处的路径必须是一个普通的非认证用户可以访问到的,否则你就进入了一个重定向的死循环,参考“避免常见陷阱”。
值类型:string
默认值:/login_check
这是你的表单所必须提交的某处页面的路由或路径。防火墙将拦截任何对此URL的请求(默认时只针对POST
请求),并处理提交过来的登录凭据(credentials)。
确保这个链接被你的主防火墙所覆盖(即,不要仅为check_path
URL创建一个独立的防火墙)
值类型:boolean
默认值:false
如果你希望用户被foward(推送)到登录表单而不是被重定向到那里,设置此选项为true
。
值类型:string
默认值:_username
这是你应该给予的登陆表单之“用户名”字段的变量名字。当你提交表单到check_path
时,security系统会在POST参数中寻找这个名字。
值类型:string
默认值:_password
这是你应该给予的登陆表单之“用户名”字段的变量名字。当你提交表单到check_path
时,security系统会在POST参数中寻找这个名字。
值类型:boolean
默认值:true
默认时,你必须以POST请求来将登录表单提交到check_path
。设置此选项为false
,即可发送GET请求到check_path
URL了。
always_use_default_target_path
(值类型:boolean
,默认值false
)
default_target_path
(值类型:string
,默认值/
)
target_path_parameter
(值类型:string
,默认值_target_path
)
use_referer
(值类型:boolean
,默认值false
)
值类型:boolean
默认值:true
默认时,当用户从防火墙中登出时,其session将会失效。这意味着从一个防火墙登出,也将自动从其他所有防火墙中登出。
invalidate_session
选项允许重新定义此种行为。在每一个防火墙中都将此选项设置为false
,则用户只能从当前防火墙中退出,而不会影响到其他的。
有几个选项是用于连接LDAP服务器的,使用form_login_ldap
和http_basic_ldap
authentication providers配合ldap
user provider。
更多细节请参考 针对LDAP服务器进行身份认证。
你可以对一台LDAP服务器进行认证,使用诸如form_login
和http_basic
等authentication providers的LDAP变体即可。只需使用form_login_ldap
和http_basic_ldap
,即可尝试bind
(绑定)某台LDAP服务器,而不是使用密码比对(password comparison)。
值类型:string
默认值:ldap
这是你配置的LDAP客户端的名字。
值类型:string
默认值:{username}
这是个字符串,将用于DN绑定。{username}
占位符将被替换成“由用户提供的”值(即他的登录)。根据你LDAP服务器的配置,你也许需要覆写这个值。
用户的取出仍然是从已配置的user provider中进行。如果你希望从一台LDAP服务器上取出用户,你需要使用ldap
user provider,此外还要配合以下两种authentication provider之一(form_login_ldap
或http_basic_ldap
)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | # app/config/security.yml
security:
# ...
providers:
my_ldap_users:
ldap:
service: ldap
base_dn: "dc=symfony,dc=com"
search_dn: "%ldap.search_dn%"
search_password: "%ldap.search_password%'
default_roles: ""
uid_key: "uid"
filter: "(&({uid_key}={username})(objectclass=person)(ou=Users))" |
PBKDF2加密器,提供了一种高级别的密码学安全性,被National Institute of Standards and Technology (NIST)(美国国家标准及技术研究所)推荐。
在本页的YAML配置区块中,你可以看到一个pbkdf2
encoder的示例。
但是使用PBKDF2也带来了一个警告:使用它(以一个较大的迭代数字)会拖慢(加密)进程。因此,在使用PBKDF2时要特别警惕和小心。
一个较好的配置,应该设成至少1000次迭代(iterations),并且使用shar512作为hash算法。
1 2 3 4 5 6 7 8 | # app/config/security.yml
security:
# ...
encoders:
Symfony\Component\Security\Core\User\User:
algorithm: bcrypt
cost: 15 |
1 2 3 4 5 6 7 8 9 | <!-- app/config/security.xml -->
<config>
<!-- ... -->
<encoder
class="Symfony\Component\Security\Core\User\User"
algorithm="bcrypt"
cost="15"
/>
</config> |
cost
取值可以是4-31
,它决定的是一个密码被加密时所耗费的时长。cost
的每一次递增,会双倍耗费它加密密码的时间。
如果你没有提供cost
选项,默认使用的取值是13
。
你可以在随时改变cost值——甚至你已经有了用另外一个cost值来加密的密码。新密码将使用新值来加密,而既存的密码,将通过使用“之前它们被加密时的cost”来验证。
每一个新密码都会自动地生成一个salt值,并不需要被持久化(译注:persisting,入库)。因为一个被加密过的密码,已经包含了这个“用作加密”的salt,仅对密码本身进行持久化已经足够。
所有加密的密码都是60
个字符的长度,所以请确保划分出足够的空间来对其进行持久化。
多数程序只需一个firewall即防火墙。但如果你的程序确实需要使用多个防火墙,你需要注意一下,如果你正在一个防火墙里面进行认证,你将不会自动地在另外一个防火墙里展开认证。换句话说,系统并不去共享一个通常所说的“context”(上下文):每一个防火墙如同工作在一个独立的安全系统之中。
然而,每一个防火墙都有一个可选的context
键(其默认值就是它所在的防火墙的名字),在向session存入/取出“security数据”时,它要被用到。如果这个键在多个防火墙中被设置为同一个名字,则“context”将被真切地“共享”:
1 2 3 4 5 6 7 8 9 10 11 | # app/config/security.yml
security:
# ...
firewalls:
somename:
# ...
context: my_context
othername:
# ...
context: my_context |
1 2 3 4 5 6 7 8 9 | <!-- app/config/security.xml -->
<security:config>
<firewall name="somename" context="my_context">
<! ... ->
</firewall>
<firewall name="othername" context="my_context">
<! ... ->
</firewall>
</security:config> |
使用HTTP-Digest认证,你需要提供一个realm(范围)和一个secret(密钥):
1 2 3 4 5 6 7 | # app/config/security.yml
security:
firewalls:
somename:
http_digest:
secret: "%secret%"
realm: 'secure-api' |
1 2 3 4 5 6 | <!-- app/config/security.xml -->
<security:config>
<firewall name="somename">
<http-digest secret="%secret%" realm="secure-api" />
</firewall>
</security:config> |
本文,包括例程代码在内,采用的是 Creative Commons BY-SA 3.0 创作共用授权。