多个入口点在 Symfony 4.4 中不起作用
Multiple entry points not working in Symfony 4.4
我在网站上有 2 种用户类型:用户和供应商。这些类型中的每一种都将使用自己的登录表单。因此,我决定在 security.yaml:
中创建 2 个单独的防火墙
security:
encoders:
App\Entity\Main\User:
algorithm: bcrypt
App\Entity\Main\Vendor:
algorithm: bcrypt
providers:
users_provider:
entity:
class: App\Entity\Main\User
property: email
vendors_provider:
entity:
class: App\Entity\Main\Vendor
property: email
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
pattern: ^/
anonymous: ~
provider: users_provider
form_login:
check_path: security_login
login_path: security_login
csrf_token_generator: security.csrf.token_manager
csrf_parameter: _csrf_token
csrf_token_id: authenticate
use_referer: true
target_path_parameter: go_to
logout:
path: security_logout
vendor:
pattern: ^/vendor/
anonymous: ~
provider: vendors_provider
form_login:
check_path: security_vendor_login
login_path: security_vendor_login
csrf_token_generator: security.csrf.token_manager
csrf_parameter: _csrf_token
csrf_token_id: authenticate
use_referer: true
target_path_parameter: go_to
logout:
path: security_logout
access_control:
- { path: ^/%locales%/login, roles: ['IS_AUTHENTICATED_ANONYMOUSLY'] }
- { path: ^/%locales%/vendor, roles: ['IS_AUTHENTICATED_ANONYMOUSLY'] }
- { path: ^/%locales%, roles: ['IS_AUTHENTICATED_ANONYMOUSLY'] }
用户用户的登录表单-login.html.twig:
{% extends 'main/base.html.twig' %}
{% block content %}
<form action="{{ path('security_login') }}"
method="POST">
<input type="text"
id="email-field"
class="form-control"
name="_username"
value="{{ form._username.vars.value }}">
<input type="password" id="password-field" class="form-control"
name="_password">
<input type="hidden" id="csrf" name="_csrf_token"
value="{{ csrf_token('authenticate') }}">
</form>
{% endblock %}
Vendor 的登录表单 vendor-login.html.twig:
{% extends 'main/base.html.twig' %}
{% block content %}
<form action="{{ path('security_vendor_login') }}"
method="POST">
<input type="text"
id="email-field"
class="form-control"
name="_username"
value="{{ form._username.vars.value }}">
<input type="password" id="password-field" class="form-control"
name="_password">
<input type="hidden" id="csrf" name="_csrf_token"
value="{{ csrf_token('authenticate') }}">
</form>
{% endblock %}
登录路由定义在routes.yaml:
security_login:
path: /login
controller: App\Controller\Main\SecurityController:loginAction
methods: [GET, POST]
security_vendor_login:
path: /vendor/login
controller: App\Controller\Main\SecurityController:vendorLoginAction
methods: [GET, POST]
以及 SecurityController 中的登录方法:
public function userLoginAction(Request $request)
{
$error = $this->authenticationUtils->getLastAuthenticationError();
$lastUsername = $this->authenticationUtils->getLastUsername();
$form = $this->formFactory->create(LoginForm::class, [
'_username' => $lastUsername
]);
return new Response(
$this->twigService->render(
'main/security/user-login.html.twig',
[
'form' => $form->createView(),
'error' => $error,
]
),
200
);
}
public function vendorLoginAction(Request $request)
{
$error = $this->authenticationUtils->getLastAuthenticationError();
$lastUsername = $this->authenticationUtils->getLastUsername();
$form = $this->formFactory->create(LoginForm::class, [
'_username' => $lastUsername
]);
return new Response(
$this->twigService->render(
'main/security/vendor-login.html.twig',
[
'form' => $form->createView(),
'error' => $error,
]
),
200
);
}
当我使用 /login 路由时,我将以用户身份成功登录。但是,如果我转到 /vendor/login 页面并提交电子邮件和密码,该页面只会刷新而不会出现任何错误消息,并且我不会通过身份验证。
在 var/log/dev.log 中我看到了这个
[2020-01-23 17:12:05] security.INFO: Populated the TokenStorage with an anonymous Token. []
知道为什么会这样吗?
这是工作 security.yml 和一些评论。防火墙的正确顺序很重要。在每个防火墙的模式定义中使用“^”也会破坏整个功能,即只有主防火墙可以工作。我不希望防火墙彼此共享 "context",所以对我来说这个参数不是必需的。如果您想在身份验证过程中执行某些操作,您还可以为每个防火墙添加自定义用户检查器。
security:
encoders:
App\Entity\Main\User: bcrypt
App\Entity\Main\Vendor: bcrypt
providers:
users_provider:
entity:
class: App\Entity\Main\User
property: email
vendors_provider:
entity:
class: App\Entity\Main\Vendor
property: email
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
vendor:
pattern: /vendor
anonymous: ~
provider: vendors_provider
# Custom user checker
# https://symfony.com/doc/current/security/user_checkers.html
# user_checker: App\Service\Main\VendorChecker
form_login:
check_path: security_vendor_login
login_path: security_vendor_login
csrf_token_generator: security.csrf.token_manager
csrf_parameter: _csrf_token
csrf_token_id: authenticate
use_referer: true
target_path_parameter: go_to
logout:
path: security_vendor_logout
target: /vendor
remember_me:
secret: '%env(APP_SECRET)%'
lifetime: 1209600 # 2 weeks in seconds
path: /
httponly: true
# Enable if you want that if you're authenticated in one firewall, you're automatically authenticated in another too
# Just use random but the same name in all firewalls you want to share the context with
# https://symfony.com/doc/current/reference/configuration/security.html#firewall-context
# context: my_context
main:
pattern: /
anonymous: ~
provider: users_provider
# Custom user checker
# https://symfony.com/doc/current/security/user_checkers.html
# user_checker: App\Service\Main\UserChecker
form_login:
check_path: security_login
login_path: security_login
csrf_token_generator: security.csrf.token_manager
csrf_parameter: _csrf_token
csrf_token_id: authenticate
use_referer: true
target_path_parameter: go_to
logout:
path: security_logout
target: /
remember_me:
secret: '%env(APP_SECRET)%'
lifetime: 1209600 # 2 weeks in seconds
path: /
httponly: true
# Enable if you want that if you're authenticated in one firewall, you're automatically authenticated in another too
# https://symfony.com/doc/current/reference/configuration/security.html#firewall-context
# context: my_context
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/vendor/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, role: IS_AUTHENTICATED_ANONYMOUSLY }
# Add your access control rules
我在网站上有 2 种用户类型:用户和供应商。这些类型中的每一种都将使用自己的登录表单。因此,我决定在 security.yaml:
中创建 2 个单独的防火墙security:
encoders:
App\Entity\Main\User:
algorithm: bcrypt
App\Entity\Main\Vendor:
algorithm: bcrypt
providers:
users_provider:
entity:
class: App\Entity\Main\User
property: email
vendors_provider:
entity:
class: App\Entity\Main\Vendor
property: email
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
pattern: ^/
anonymous: ~
provider: users_provider
form_login:
check_path: security_login
login_path: security_login
csrf_token_generator: security.csrf.token_manager
csrf_parameter: _csrf_token
csrf_token_id: authenticate
use_referer: true
target_path_parameter: go_to
logout:
path: security_logout
vendor:
pattern: ^/vendor/
anonymous: ~
provider: vendors_provider
form_login:
check_path: security_vendor_login
login_path: security_vendor_login
csrf_token_generator: security.csrf.token_manager
csrf_parameter: _csrf_token
csrf_token_id: authenticate
use_referer: true
target_path_parameter: go_to
logout:
path: security_logout
access_control:
- { path: ^/%locales%/login, roles: ['IS_AUTHENTICATED_ANONYMOUSLY'] }
- { path: ^/%locales%/vendor, roles: ['IS_AUTHENTICATED_ANONYMOUSLY'] }
- { path: ^/%locales%, roles: ['IS_AUTHENTICATED_ANONYMOUSLY'] }
用户用户的登录表单-login.html.twig:
{% extends 'main/base.html.twig' %}
{% block content %}
<form action="{{ path('security_login') }}"
method="POST">
<input type="text"
id="email-field"
class="form-control"
name="_username"
value="{{ form._username.vars.value }}">
<input type="password" id="password-field" class="form-control"
name="_password">
<input type="hidden" id="csrf" name="_csrf_token"
value="{{ csrf_token('authenticate') }}">
</form>
{% endblock %}
Vendor 的登录表单 vendor-login.html.twig:
{% extends 'main/base.html.twig' %}
{% block content %}
<form action="{{ path('security_vendor_login') }}"
method="POST">
<input type="text"
id="email-field"
class="form-control"
name="_username"
value="{{ form._username.vars.value }}">
<input type="password" id="password-field" class="form-control"
name="_password">
<input type="hidden" id="csrf" name="_csrf_token"
value="{{ csrf_token('authenticate') }}">
</form>
{% endblock %}
登录路由定义在routes.yaml:
security_login:
path: /login
controller: App\Controller\Main\SecurityController:loginAction
methods: [GET, POST]
security_vendor_login:
path: /vendor/login
controller: App\Controller\Main\SecurityController:vendorLoginAction
methods: [GET, POST]
以及 SecurityController 中的登录方法:
public function userLoginAction(Request $request)
{
$error = $this->authenticationUtils->getLastAuthenticationError();
$lastUsername = $this->authenticationUtils->getLastUsername();
$form = $this->formFactory->create(LoginForm::class, [
'_username' => $lastUsername
]);
return new Response(
$this->twigService->render(
'main/security/user-login.html.twig',
[
'form' => $form->createView(),
'error' => $error,
]
),
200
);
}
public function vendorLoginAction(Request $request)
{
$error = $this->authenticationUtils->getLastAuthenticationError();
$lastUsername = $this->authenticationUtils->getLastUsername();
$form = $this->formFactory->create(LoginForm::class, [
'_username' => $lastUsername
]);
return new Response(
$this->twigService->render(
'main/security/vendor-login.html.twig',
[
'form' => $form->createView(),
'error' => $error,
]
),
200
);
}
当我使用 /login 路由时,我将以用户身份成功登录。但是,如果我转到 /vendor/login 页面并提交电子邮件和密码,该页面只会刷新而不会出现任何错误消息,并且我不会通过身份验证。 在 var/log/dev.log 中我看到了这个
[2020-01-23 17:12:05] security.INFO: Populated the TokenStorage with an anonymous Token. []
知道为什么会这样吗?
这是工作 security.yml 和一些评论。防火墙的正确顺序很重要。在每个防火墙的模式定义中使用“^”也会破坏整个功能,即只有主防火墙可以工作。我不希望防火墙彼此共享 "context",所以对我来说这个参数不是必需的。如果您想在身份验证过程中执行某些操作,您还可以为每个防火墙添加自定义用户检查器。
security:
encoders:
App\Entity\Main\User: bcrypt
App\Entity\Main\Vendor: bcrypt
providers:
users_provider:
entity:
class: App\Entity\Main\User
property: email
vendors_provider:
entity:
class: App\Entity\Main\Vendor
property: email
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
vendor:
pattern: /vendor
anonymous: ~
provider: vendors_provider
# Custom user checker
# https://symfony.com/doc/current/security/user_checkers.html
# user_checker: App\Service\Main\VendorChecker
form_login:
check_path: security_vendor_login
login_path: security_vendor_login
csrf_token_generator: security.csrf.token_manager
csrf_parameter: _csrf_token
csrf_token_id: authenticate
use_referer: true
target_path_parameter: go_to
logout:
path: security_vendor_logout
target: /vendor
remember_me:
secret: '%env(APP_SECRET)%'
lifetime: 1209600 # 2 weeks in seconds
path: /
httponly: true
# Enable if you want that if you're authenticated in one firewall, you're automatically authenticated in another too
# Just use random but the same name in all firewalls you want to share the context with
# https://symfony.com/doc/current/reference/configuration/security.html#firewall-context
# context: my_context
main:
pattern: /
anonymous: ~
provider: users_provider
# Custom user checker
# https://symfony.com/doc/current/security/user_checkers.html
# user_checker: App\Service\Main\UserChecker
form_login:
check_path: security_login
login_path: security_login
csrf_token_generator: security.csrf.token_manager
csrf_parameter: _csrf_token
csrf_token_id: authenticate
use_referer: true
target_path_parameter: go_to
logout:
path: security_logout
target: /
remember_me:
secret: '%env(APP_SECRET)%'
lifetime: 1209600 # 2 weeks in seconds
path: /
httponly: true
# Enable if you want that if you're authenticated in one firewall, you're automatically authenticated in another too
# https://symfony.com/doc/current/reference/configuration/security.html#firewall-context
# context: my_context
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/vendor/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, role: IS_AUTHENTICATED_ANONYMOUSLY }
# Add your access control rules