在AngularJS中注册FOSUserBundle



我有一个SPA web应用程序,使用AngularJS作为前端,Symfony2作为后端。

我用FOSUserBundle处理User

我现在想做的是使用AngularJS方法注册我的User也就是通过Ajax

我的问题是每当我提交表单时,它都会在控制台日志中打印"invalid form"

这是我目前的进度:

new.html

<form class="form-group text-left" ng-submit="submit()" novalidate name="userFrm">
    <div class="form-group">
        <label for="user.email" class="required">Email</label>
        <input id="user.email" name="user.email" class="form-control" type="text" ng-model="user.email" />
    </div>
    <div class="form-group">
        <label for="user.username" class="required">Username</label>
        <input id="user.username" name="user.username" class="form-control" type="text" ng-model="user.username" />
    </div>
    <div class="form-group">
        <label for="user.plainPassword" class="required">Password</label>
        <input id="user.plainPassword" name="user.plainPassword" class="form-control" type="password" ng-model="user.plainPassword" />
    </div>
    <div class="form-group">
        <label for="confirmPassword" class="required">Confirm Password</label>
        <input id="confirmPassword" name="confirmPassword" compare-to="user.plainPassword" class="form-control" type="password" ng-model="confirmPassword" />
    </div>
    <input type="submit" value="Register" ng-disabled="userFrm.$invalid"  class="btn btn-primary center-block col-lg-2" />
</form>

new.js

'use strict';
(function () {
    angular.module('myApp.user.new', [])
        .config(['$stateProvider', function ($stateProvider) {
                $stateProvider
                        .state('user.new', {
                            url: "/new",
                            controller: "NewUserCtrl",
                            templateUrl: PATH + 'user/new/new.html'
                        });
            }])
        .controller('NewUserCtrl', ["$scope", "$http", "$state", function ($scope, $http, $state) {
                var success = function (response) {
                    var valid = response.data.valid;
                    if (valid) {
                        $state.go('home');
                    } else {
                        console.log("invalid form");
                    }
                };
                var error = function (reason) {
                    console.log("Submission failed");
                };
                $scope.submit = function () {
                    var formData = {
                        fos_user_registration: $scope.user,
                        confirmPass: $scope.confirmPassword
                    };
                    $http.post(Routing.generate('fos_user_registration_register'), $.param(formData), {
                        headers: {'Content-Type': 'application/x-www-form-  urlencoded'}
                    })
                            .then(success, error);
                };
            }]);
}());

RegistrationController.php(从FOSUserBundle覆盖)

public function registerAction(Request $request) {
    /** @var $formFactory FOSUserBundleFormFactoryFactoryInterface */
    $formFactory = $this->get('fos_user.registration.form.factory');
    /** @var $userManager FOSUserBundleModelUserManagerInterface */
    $userManager = $this->get('fos_user.user_manager');
    $user = $userManager->createUser();
    $user->setEnabled(true);
    $form = $formFactory->createForm();
    $form->setData($user);
    $form->handleRequest($request);
    if ($form->isValid()) {
        $user->addRole('ROLE_ADMIN');
        $userManager->updateUser($user);
        $response = ['valid' => true];
        return new JsonResponse($response);
    }

   $response = ['valid' => false];
   return new JsonResponse($response);
}

我在您的表单中没有看到CSRF令牌。如果没有CSRF令牌,您的表单可能无法验证。先检查这里;http://symfony.com/doc/current/cookbook/security/csrf_in_login_form.html

此外,为了完全兼容,使用twig模板引擎生成表单可能会更好。在这里看到的;http://symfony.com/doc/current/book/forms.html

为了进一步调查为什么您的表单没有被验证,您可以为$form->isValid()检查编写一个else块,并使用答案中的方法来查看表单错误。您可以检查表单没有被验证的原因。https://stackoverflow.com/a/17428869/3399234

我想到了一个解决办法。我使用了包含symfony 2.6.10的Vagrant配置。我已经覆盖了RegistrationFormType,将它放在我自己的bundle中,并将其作为服务注入,就像FOS一样。我用我自己的服务别名替换了FOS登记表。所以我设法关闭csrf保护在我的覆盖RegistrationFormType。

还添加了将plainPassword设置为用户模型,以修复USerManager中的持久性错误。

控制器,覆盖FOS注册控制器。

<?php
namespace AcmeWebBundleController;
use SymfonyBundleFrameworkBundleControllerController;
use FOSUserBundleControllerRegistrationController as BaseController;
use SymfonyComponentHttpFoundationRequest as Request;
use SymfonyComponentHttpFoundationJsonResponse as JsonResponse;
class RegistrationController extends BaseController
{
     public function registerAction()
        {
            $request = Request::createFromGlobals();
            $form = $this->container->get('fos_user.registration.form');
            /** @var $userManager FOSUserBundleModelUserManagerInterface */
            $userManager = $this->container->get('fos_user.user_manager');
            $user = $userManager->createUser();
            $form->setData($user);
            $form->handleRequest($request);
            if ($form->isValid()) {             
                $user->setEnabled(true);
                $user->addRole('ROLE_ADMIN');
                $userManager->updateUser($user);
                $response = ['valid' => true];
                return new JsonResponse($response);
            } else {
                $string = (string) $form->getErrors(true, false);
                //Show errors
                $response = ['valid' => false];
                return new JsonResponse($response);
            }
           return $this->container->get('templating')->renderResponse('AcmeWebBundle:Default:index.html.twig');
        }
}

被覆盖的FOS注册表,

<?php
//AcmeWebBundleFormTypeRegistrationFormType.php
namespace AcmeWebBundleFormType;
use SymfonyComponentFormAbstractType;
use SymfonyComponentFormFormBuilderInterface;
use SymfonyComponentOptionsResolverOptionsResolverInterface;
class RegistrationFormType extends AbstractType
{
    private $class;
    /**
     * @param string $class The User class name
     */
    public function __construct($class)
    {
        $this->class = $class;
    }
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => $this->class,
            'intention'  => 'registration',
            'csrf_protection' => false, //this line does the trick ;)
        ));
    }
    public function getParent()
    {
        return 'fos_user_registration';
    }
    public function getName()
    {
        return 'acme_user_registration';
    }
}

Services.yml

services:
    acme.registration.form.type:
        class: AcmeWebBundleFormTypeRegistrationFormType
        arguments: ["%fos_user.model.user.class%"]
        tags:
            - { name: form.type, alias: acme_user_registration }

index.html.twig

     <script type="text/javascript">
                       var app = angular.module('myApp',  []);
                            app.controller('NewUserCtrl', ["$scope", "$http", function ($scope, $http) {
                                    var success = function (response) {
                                        var valid = response.data.valid;
                                        if (valid) {
                                            $state.go('home');
                                        } else {
                                            console.log("invalid form");
                                        }
                                    };
                                    var error = function (reason) {
                                        console.log("Submission failed");
                                    };
                                    $scope.submit = function () {
                                        var formData = {
                                            fos_user_registration_form: $scope.user
                                        };
                                    $http.post('<YOUR URL HERE>', $.param(formData), {
                                            headers: {'Content-Type': 'application/x-www-form-urlencoded'}
                                        }).then(success, error);
                                    };
                                }]);
                </script>
<div id="content" ng-app="myApp" ng-controller="NewUserCtrl" >
    <form class="form-group text-left" ng-submit="submit()" novalidate name="userFrm">
        <div class="form-group">
            <label for="user.email" class="required">Email</label>
            <input id="user.email" name="user.email" class="form-control" type="text" ng-model="user.email" />
        </div>
        <div class="form-group">
            <label for="user.username" class="required">Username</label>
            <input id="user.username" name="user.username" class="form-control" type="text" ng-model="user.username" />
        </div>
        <div class="form-group">
            <label for="user.plainPassword.first" class="required">Password</label>
            <input id="user.plainPassword.first" name="user.plainPassword.first" class="form-control" type="password" ng-model="user.plainPassword.first" />
        </div>
        <div class="form-group">
            <label for="user.plainPassword.second" class="required">Confirm Password</label>
            <input id="user.plainPassword.second" name="user.plainPassword.second" compare-to="user.plainPassword.first" class="form-control" type="password" ng-model="user.plainPassword.second" />
        </div>
        <input type="submit" value="Register" ng-disabled="userFrm.$invalid"  class="btn btn-primary center-block col-lg-2" />
    </form>
</div>

这是config中的fos_user配置。当FOS用户包的注册表单被调用时,使用覆盖的表单更改默认表单。

config.yml

fos_user:
    registration:
        form:
             type: acme_user_registration

就是这样,我可以发布表单并将用户持久化到数据库,然后按预期返回{"valid":true}响应。最后,我有机会学习如何将AngularJS注入到Symfony 2中,为此干杯。

最新更新