Php Symfony-用户即使在名称更改时也会注销
我面临着一个非常奇怪的情况,一个具有Php Symfony-用户即使在名称更改时也会注销,php,symfony,Php,Symfony,我面临着一个非常奇怪的情况,一个具有角色的用户在我更改名称后立即注销,即使我没有更改任何内容并按下保存按钮,它也会注销。如果我将用户在数据库中的角色直接更改为role\u user,则相同的代码工作正常,用户不会注销 以下是负责配置文件更新的控制器 /** * @Route("/profile", name="profile") */ public function profileAction(Request $request) {
角色的用户在我更改名称后立即注销,即使我没有更改任何内容并按下保存按钮,它也会注销。如果我将用户在数据库中的角色直接更改为role\u user
,则相同的代码工作正常,用户不会注销
以下是负责配置文件更新的控制器
/**
* @Route("/profile", name="profile")
*/
public function profileAction(Request $request)
{
$em = $this->getDoctrine()->getManager();
$userInfo = $this->getUser();
//create the form object
$profileForm = $this->createForm(UserType::class, $userInfo);
$profileForm->handleRequest($request);
//check data validity
if($profileForm->isValid()){
$em->persist($userInfo);
$em->flush();
$this->get('session')->getFlashBag()->add(
'success',
'Your profile information has been updated'
);
return $this->render('AppBundle:admin/user:admin-edit.html.twig',array(
'edit_form' => $profileForm->createView()
));
}
// render registration form
return $this->render('AppBundle:admin/user:admin-edit.html.twig',array(
'edit_form' => $profileForm->createView()
));
}
}
这是我的security.yml
security:
encoders:
# Our user class and the algorithm we'll use to encode passwords
# http://symfony.com/doc/current/book/security.html#encoding-the-user-s-password
AppBundle\Entity\User: bcrypt
providers:
# Simple example of loading users via Doctrine
# To load users from somewhere else: http://symfony.com/doc/current/cookbook/security/custom_provider.html
database_users:
entity: { class: AppBundle:User, property: username }
firewalls:
# disables authentication for assets and the profiler, adapt it according to your needs
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
http_basic: ~
anonymous: ~
logout: ~
guard:
authenticators:
- app.form_login_authenticator
- app.facebook_authenticator
# by default, use the start() function from FormLoginAuthenticator
entry_point: app.form_login_authenticator
access_control:
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/, roles: ROLE_ADMIN }
- { path: ^/user, roles: ROLE_USER }
更新1
这是我的UserType
namespace AppBundle\Form;
use AppBundle\Form\EventListener\AddDepartmentDegreeCourseFieldSubscriber;
use AppBundle\Form\EventListener\AddProfileFieldSubscriber;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class UserType extends AbstractType
{
private $addDepartmentDegreeCourseFieldSubscriber;
private $addProfileFieldSubscriver;
function __construct(AddDepartmentDegreeCourseFieldSubscriber $subscriber, AddProfileFieldSubscriber $fields)
{
$this->addDepartmentDegreeCourseFieldSubscriber = $subscriber;
$this->addProfileFieldSubscriver = $fields;
}
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->addEventSubscriber($this->addProfileFieldSubscriver);
$builder->addEventSubscriber($this->addDepartmentDegreeCourseFieldSubscriber);
}
/**
* @param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\User'
));
}
}
这是我的AddProfileFieldSubscriber
namespace AppBundle\Form\EventListener;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationChecker;
use Symfony\Component\Validator\Constraints\NotBlank;
class AddProfileFieldSubscriber implements EventSubscriberInterface
{
protected $authorizationChecker;
function __construct(AuthorizationChecker $authorizationChecker)
{
$this->authorizationChecker = $authorizationChecker;
}
public static function getSubscribedEvents()
{
// Tells the dispatcher that you want to listen on the form.pre_set_data
// event and that the preSetData method should be called.
return array(FormEvents::PRE_SET_DATA => 'preSetData');
}
public function preSetData(FormEvent $event)
{
$user = $event->getData();
$form = $event->getForm();
if($user){
$form->add('firstName', TextType::class);
$form->add('lastName', TextType::class);
$form->add('password', PasswordType::class, array(
'mapped' => false
));
$form->add('profileImage', FileType::class, array(
'data_class' => null
));
if (in_array("ROLE_USER", $user->getRoles())) {
$form->add('contactNumber', TextType::class);
$form->add('gender', ChoiceType::class, array(
'choices' => array(
'Male' => 'm',
'Female' => 'f'
),
'placeholder' => 'provide_gender'
));
$form->add('college', EntityType::class, array(
'placeholder' => 'provide_college',
'class' => 'AppBundle\Entity\College')
);
$form->add('interest', EntityType::class, array(
'class' => 'AppBundle\Entity\Interest',
'multiple' => true,
'expanded' => false,
'by_reference' => false,
)
);
}
if($this->authorizationChecker->isGranted('ROLE_ADMIN') ) {
$form->add('isActive', ChoiceType::class, array(
'choices' => array(
'account_active' => '1',
'account_inactive' => '0'
),
'placeholder' => 'provide_status'
));
}
}
//if the selected user has role_user only then display the following fields in edit profile view
else {
$form->add('username', EmailType::class);
$form->add('password', PasswordType::class, array(
'constraints' => array(new NotBlank(array(
'message' => 'user.password.not_blank'
)
),),
));
}
}
}
这是AddDepartmentDegreeCourseFieldSubscriber
namespace AppBundle\Form\EventListener;
use AppBundle\Entity\Degree;
use AppBundle\Entity\Department;
use Doctrine\ORM\EntityManager;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\FormInterface;
class AddDepartmentDegreeCourseFieldSubscriber implements EventSubscriberInterface
{
protected $em;
function __construct(EntityManager $em)
{
$this->em = $em;
}
public static function getSubscribedEvents()
{
// Tells the dispatcher that you want to listen on the form.pre_set_data
// event and that the preSetData method should be called.
return array(
FormEvents::PRE_SET_DATA => 'onPreSetData',
FormEvents::PRE_SUBMIT => 'onPreSubmit'
);
}
protected function addElements(FormInterface $form, Department $departments = null, Degree $degree = null)
{
// Add the department element
$form->add('department', EntityType::class, array(
'data' => $departments,
'placeholder' => 'provide_department',
'class' => 'AppBundle\Entity\Department')
);
// Degree are empty, unless we actually supplied a department
$degree = array();
if ($departments) {
// Fetch the courses from specified degree
$repo = $this->em->getRepository('AppBundle:Degree');
$degree = $repo->findByDepartment($departments, array('name' => 'asc'));
}
// Add the province element
$form->add('degree', EntityType::class, array(
'placeholder' => 'provide_degree',
'class' => 'AppBundle\Entity\Degree',
'choices' => $degree)
);
// Cities are empty, unless we actually supplied a province
$courses = array();
if ($degree) {
// Fetch the cities from specified province
$repo = $this->em->getRepository('AppBundle:Course');
$courses = $repo->findByDegree($degree, array('name' => 'asc'));
}
// Add the Course element
$form->add('course', EntityType::class, array(
'class' => 'AppBundle\Entity\Course',
'choices' => $courses,
));
}
function onPreSubmit(FormEvent $event) {
$form = $event->getForm();
$data = $event->getData();
if (isset($data['degree'])) {
// Note that the data is not yet hydrated into the entity.
$degree = $this->em->getRepository('AppBundle:Degree')->find($data['degree']);
$department = $this->em->getRepository('AppBundle:Department')->find($data['department']);
$this->addElements($form, $department, $degree);
}
}
function onPreSetData(FormEvent $event) {
//echo "before submit";die;
$user = $event->getData();
$form = $event->getForm();
if($user){
//if the selected user has role_user only then display the following fields in edit profile view
if (in_array("ROLE_USER", $user->getRoles())) {
$degree = ( !empty($user) && !empty($user->getCourse())) ? $user->getCourse()->getDegree() : null;
$departments = ( !empty($user) && !empty($user->getCourse())) ? $user->getCourse()->getDegree()->getDepartment() : null;
$this->addElements($form, $departments, $degree);
}
}
}
}
在这一点上,我真的不知道是什么原因导致了这一点,我将非常感谢这里的任何帮助…您提供的内容中有很多错误。这些因素可能会导致你所看到的行为
安全规则
在security.yml中,您有以下行:
- { path: ^/admin/, roles: ROLE_ADMIN }
这意味着,如果用户访问此模式,任何不使用ROLE_ADMIN的用户都将返回登录屏幕
同时,在控制器中,您总是将用户引导回基于管理员的路由:
/*
* @Route("admin/profile", name="admin_profile")
*/
这意味着,无论他们做什么,他们总是发送到一个管理模式。这意味着,如果他们改变角色,他们将被防火墙踢出
控制器
在控制器中,您将用户实体绑定到formtype,很好。但是,你编码的方式意味着你不了解它是如何工作的
调用handleRequest
时,Symfony从表单中提取数据(如果已提交),并将其与传递给它的实体“合并”。这意味着您不必调用对象上的任何setter,因为所有这些都已经为您完成了
用户实体
您的用户
实体上应该有一个普通密码
字段和一个密码
字段。该表单仅映射到PlainPassword
字段。。然后,在控制器中,获取PlainPassword
值,对其进行编码,将其设置为实体的Password
字段,并确保清除PlainPassword
值(您不想存储该值)。如果您已经在自定义用户实体上实现了UserInterface
(您应该有),那么您应该有一个名为eraseCredentials
的方法,这就是它的用途
这样做的结果是,当您检查某些东西(例如新密码)时,您只需执行以下操作:
if($profileForm->isValid()){
// $userInfo is populated by handleRequest
if ($userInfo->getPlainPassword()) {
// do your encoding/erasing credentials here
}
// ...
}
我还建议您编写一个适当的UserManager
类来处理这些事情。它将事情集中起来,使调试更容易
如果您使用的是我在示例中编写的内容,这也意味着当您想要更新用户信息时,您只需调用$userManager->updateUser($user)
,它将为您完成所有繁琐的工作。您提供的内容有很多错误。这些因素可能会导致你所看到的行为
安全规则
在security.yml中,您有以下行:
- { path: ^/admin/, roles: ROLE_ADMIN }
这意味着,如果用户访问此模式,任何不使用ROLE_ADMIN的用户都将返回登录屏幕
同时,在控制器中,您总是将用户引导回基于管理员的路由:
/*
* @Route("admin/profile", name="admin_profile")
*/
这意味着,无论他们做什么,他们总是发送到一个管理模式。这意味着,如果他们改变角色,他们将被防火墙踢出
控制器
在控制器中,您将用户实体绑定到formtype,很好。但是,你编码的方式意味着你不了解它是如何工作的
调用handleRequest
时,Symfony从表单中提取数据(如果已提交),并将其与传递给它的实体“合并”。这意味着您不必调用对象上的任何setter,因为所有这些都已经为您完成了
用户实体
您的用户
实体上应该有一个普通密码
字段和一个密码
字段。该表单仅映射到PlainPassword
字段。。然后,在控制器中,获取PlainPassword
值,对其进行编码,将其设置为实体的Password
字段,并确保清除PlainPassword
值(您不想存储该值)。如果您已经在自定义用户实体上实现了UserInterface
(您应该有),那么您应该有一个名为eraseCredentials
的方法,这就是它的用途
这样做的结果是,当您检查某些东西(例如新密码)时,您只需执行以下操作:
if($profileForm->isValid()){
// $userInfo is populated by handleRequest
if ($userInfo->getPlainPassword()) {
// do your encoding/erasing credentials here
}
// ...
}
我还建议您编写一个适当的UserManager
类来处理这些事情。它将事情集中起来,使调试更容易
如果您使用了我在示例中编写的内容,这也意味着当您想要更新用户信息时,只需调用$userManager->updateUser($user)
它将为您完成所有的繁琐工作。关于安全性。yml
是的,为了访问任何以admin
开头的路径,您需要有角色\u admin
,这样设置就可以了,我明白你对密码的看法,我会这样做,但你的建议并不能解决问题,假设我创建了一个配置文件路由,ROLE\u USER
可以在控制器内部使用相同的代码进行访问,一切正常。只有这个ROLE\u ADMIN
可以很好地更新它的配置文件,但是它会被注销。。。我不明白为什么它会被注销。我更新了我的问题,删除了里面的所有内容