问题描述
我有一个旧的Symfony 3.1网站,我先升级到Symfony 3.4.x,然后又升级到Symfony 4.4.11,但是我没有将其升级到symfony flex。我修复了许多问题,公共站点似乎正常运行。
我不得不重建身份验证,因为旧的与sf4不兼容。
我遵循了 https://symfony.com/doc/4.4/security/form_login_setup.html
和: https://symfonycasts.com/screencast/symfony-security/make-user
我遇到了这样一种情况,即在成功认证之后,当它重定向到管理区域时,它总是再次检查LoginFormAuthenticator,这显然不支持管理区域,并且它以匿名用户的身份重定向回到登录页面。 / p>
关于此问题,有许多讨论,并尝试了所有我发现的问题,但没有找到解决方案。甚至没有调试它。
会话保存在定义的路径中。其ID与浏览器中的PHPSESSID相同。 网站运行HTTP协议。
security.yml
security:
encoders:
AppBundle\Entity\User:
algorithm: bcrypt
cost: 12
providers:
user_provider:
entity:
class: AppBundle:User
property: email
firewalls:
dev:
pattern: ^/(_(profiler|wdt|error)|css|images|js)/
security: false
main:
stateless: true
pattern: ^/
anonymous: true
logout_on_user_change: true
guard:
authenticators:
- AppBundle\Security\LoginFormAuthenticator
form_login:
provider: user_provider
username_parameter: email
csrf_token_generator: security.csrf.token_manager
login_path: app_login
logout:
path: app_logout
access_control:
- { path: ^/admin,roles: ROLE_ADMIN }
- { path: ^/,roles: IS_AUTHENTICATED_ANONYMOUSLY }
路由:
app_login:
path: /login
defaults: { _controller: AppBundle\Controller\BackendController:loginAction }
app_logout:
path: /logout
defaults: { _controller: AppBundle\Controller\BackendController:logoutAction }
app_admin:
path: /admin/{page}/{entry}
defaults: { _controller: AppBundle\Controller\BackendController:showAction,entry: null }
User.php
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\EquatableInterface;
use Symfony\Component\Security\Core\User\UserInterface;
/**
* User
*
* @ORM\Table(name="user")
* @ORM\Entity(repositoryClass="AppBundle\Repository\UserRepository")
*/
class User implements UserInterface,\Serializable,EquatableInterface
{
private $id;
// and so on
public function serialize()
{
return serialize(array(
$this->id,$this->email,$this->password
));
}
public function unserialize($serialized)
{
list (
$this->id,$this->password,) = unserialize($serialized);
}
public function getRoles()
{
return array('ROLE_ADMIN');
}
public function getUsername()
{
return $this->getEmail();
}
public function isEqualTo(UserInterface $user)
{
if (!$user instanceof User) {
return false;
}
if ($this->password !== $user->getPassword()) {
return false;
}
if ($this->salt !== $user->getSalt()) {
return false;
}
if ($this->email !== $user->getUsername()) {
return false;
}
return true;
}
}
后端控制器:
class BackendController extends AbstractController
{
public function loginAction(AuthenticationUtils $authenticationUtils)
{
return $this->render('AppBundle:Backend:page.html.twig',array(
'email' => $authenticationUtils->getLastUsername(),'error' => $authenticationUtils->getLastAuthenticationError()
));
}
public function logoutAction()
{
$this->container->get('security.token_storage')->setToken(null);
$this->container->get('request')->getSession()->invalidate();
}
public function showAction(Request $request,$page,$entry)
{
$this->denyAccessUnlessGranted('ROLE_ADMIN',null,'Unable to access this page!');
// some logic
}
}
LoginFormAuthentication.php
在示例中看起来相同,并且可以正常工作。它成功到达onAuthenticationSuccess()并重定向到管理区域。
dev.log
request.INFO: Matched route "app_login". {"route":"app_login"..}
security.DEBUG: Checking for guard authentication credentials. {"firewall_key":"main","authenticators":1} []
security.DEBUG: Checking support on guard authenticator. {"firewall_key":"main","authenticator":"AppBundle\\Security\\LoginFormAuthenticator"} []
security.DEBUG: Calling getCredentials() on guard authenticator. {"firewall_key":"main","authenticator":"AppBundle\\Security\\LoginFormAuthenticator"} []
security.DEBUG: Passing guard token information to the GuardAuthenticationProvider {"firewall_key":"main","authenticator":"AppBundle\\Security\\LoginFormAuthenticator"} []
doctrine.DEBUG: SELECT t0.* FROM user t0 WHERE t0.email = ? LIMIT 1 ["email@me.com"] []
security.INFO: Guard authentication successful! {"token":"[object] (Symfony\\Component\\Security\\Guard\\Token\\PostAuthenticationGuardToken: PostAuthenticationGuardToken(user=\"email@me.com\",authenticated=true,roles=\"ROLE_ADMIN\"))","authenticator":"AppBundle\\Security\\LoginFormAuthenticator"} []
security.DEBUG: Guard authenticator set success response. Redirect response
security.DEBUG: Remember me skipped: it is not configured for the firewall.
security.DEBUG: The "AppBundle\Security\LoginFormAuthenticator" authenticator set the response. Any later authenticator will not be called {"authenticator":"AppBundle\\Security\\LoginFormAuthenticator"} []
重定向后:
request.INFO: Matched route "app_admin". {"route":"app_admin" ..}
security.DEBUG: Checking for guard authentication credentials. {"firewall_key":"main","authenticator":"AppBundle\\Security\\LoginFormAuthenticator"} []
security.DEBUG: Guard authenticator does not support the request. {"firewall_key":"main","authenticator":"AppBundle\\Security\\LoginFormAuthenticator"} []
security.INFO: Populated the TokenStorage with an anonymous Token. [] []
security.DEBUG: Access denied,the user is not fully authenticated; redirecting to authentication entry point.
security.DEBUG: Calling Authentication entry point. [] []
解决方法
您必须更改卫士身份验证器 AppBundle \ Security \ LoginFormAuthenticator
这向警卫人员说明,您只需要检查登录页面上的凭据即可
public function supports(Request $request)
{
return 'login_route' === $request->attributes->get('_route') && $request->isMethod('POST');
}
,
我的同事找出了问题所在。上面的代码实际上有多个问题。
- 使用GuardAuthenticator接口已从sf4中删除: https://github.com/symfony/symfony/blob/4.4/UPGRADE-4.0.md#security
- 无需logout_on_user_change
- 不需要LoginFormAuthenticator。
- 无状态:true是防火墙中的错误设置,但是当我删除它时,它将引发先前的错误:“由于用户已更改,无法刷新令牌。尝试刷新令牌后,令牌已取消身份验证。”发生了,因为
- 在isEqualTo中,我检查了
$this->salt !== $user->getSalt()
,但未序列化
因此工作解决方案如下
- 路由相同
- 后端控制器是相同的
- LoginFormAuthentication.php已被删除
security.yml
security:
encoders:
AppBundle\Entity\User:
algorithm: bcrypt
cost: 12
providers:
user_provider:
entity:
class: AppBundle:User
property: email
firewalls:
dev:
pattern: ^/(_(profiler|wdt|error)|css|images|js)/
security: false
main:
anonymous: ~
provider: user_provider
form_login:
login_path: app_login
check_path: app_login
default_target_path: app_admin
logout:
path: app_logout
access_control:
- { path: ^/admin,roles: ROLE_ADMIN }
- { path: ^/,roles: IS_AUTHENTICATED_ANONYMOUSLY }
User.php
class User implements UserInterface,\Serializable,EquatableInterface
{
// ..
public function serialize()
{
return serialize(array(
$this->id,$this->email,$this->password,$this->salt,));
}
public function unserialize($serialized)
{
list (
$this->id,$this->salt
) = unserialize($serialized,array('allowed_classes' => false));
}
public function isEqualTo(UserInterface $user)
{
if (!$user instanceof User) {
return false;
}
if ($user->getId() == $this->getId()) {
return true;
}
if ($this->password !== $user->getPassword()) {
return false;
}
if ($this->salt !== $user->getSalt()) {
return false;
}
if ($this->email !== $user->getUsername()) {
return false;
}
return true;
}
}