个性化阅读
专注于IT技术分析

如何在Symfony 3上的控制器(带有或不带有FOSUserBundle)中手动验证(登录)用户

本文概述

当我们谈论用户的操纵, 登录和注册表格等时, 诸如FOSUserBundle之类的工具使事情变得非常简单, 谁能拒绝呢?可能是那些需要控制一切并了解其工作原理的人。这就是为什么某些开发人员即使不使用FOSUserBundle而是希望手动处理这些事件的原因。

寻找使用你自己的代码从控制器登录用户?你找到了学习它的正确地方。在本文中, 你将学习如何在Symfony应用程序上自动登录用户(带有或不带有凭据)。

怎么做

你首先需要在控制器中导入一些类, 即InteractiveLoginEvent和UsernamePasswordToken。然后, 使用Doctrine的实体管理器或FOSUserBundle的用户管理器自行查找用户。如果你使用的是FOSUser, 则用户应存储在变量中, 并且代表FOS \ UserBundle \ Model \ User的实例;如果不使用, 则仅表示User。接下来, 继续创建令牌并在令牌存储服务中进行设置。创建令牌的类期望将用户对象作为第一个参数, 因为第二个参数通常是用户的密码, 但是可以为null。作为第三个参数, 你需要提供要使用的防火墙的名称, 它通常是主要的, 但是如果有其他名称, 则值得检查你的security.yml文件。作为第四个参数, 你需要提供用户的角色。

你还需要将类生成的令牌存储在会话中, 最后手动调度交互式登录事件:

<?php

namespace AppBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;

class SomeController extends Controller
{
    public function loginAction(Request $request)
    {
        $user = /*The user needs to be registered */;#
        // Example of how to obtain an user:
        //$user = $this->getDoctrine()->getManager()->getRepository("AppBundle/Entity/User")->findOneBy(array('username' => "some user name example"));
        
        //Handle getting or creating the user entity likely with a posted form
        // The third parameter "main" can change according to the name of your firewall in security.yml
        $token = new UsernamePasswordToken($user, null, 'main', $user->getRoles());
        $this->get('security.token_storage')->setToken($token);

        // If the firewall name is not main, then the set value would be instead:
        // $this->get('session')->set('_security_XXXFIREWALLNAMEXXX', serialize($token));
        $this->get('session')->set('_security_main', serialize($token));
        
        // Fire the login event manually
        $event = new InteractiveLoginEvent($request, $token);
        $this->get("event_dispatcher")->dispatch("security.interactive_login", $event);
        
        /*
         * Now the user is authenticated !!!! 
         * Do what you need to do now, like render a view, redirect to route etc.
         */
    }
}

完成此操作后, 你已自动在会话中登录了一个用户, 但是未检查该用户的凭据。

定制登录控制器示例

假设你正在创建一些自定义登录表单(或覆盖FOSUserBundle的默认登录表单), 并且需要手动验证用户。为此, 第一个控制器示例仅可用于设置会话中的用户, 但是由于我们既不验证用户名也不验证密码, 因此它实际上并未进行身份验证。

在会话中设置用户之前, 我们需要做的第一步是验证他提供的凭据是否正确。为此, 我们需要控制器中的安全编码服务来检查Providen数据的真实性。在此示例中, 我们将以基本逻辑向你展示身份验证过程的工作方式:

<?php

namespace AppBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;

class SomeController extends Controller
{
    public function loginAction(Request $request)
    {
        // This data is most likely to be retrieven from the Request object (from Form)
        // But to make it easy to understand ...
        $_username = "batman";
        $_password = "batmobil";

        // Retrieve the security encoder of symfony
        $factory = $this->get('security.encoder_factory');

        /// Start retrieve user
        // Let's retrieve the user by its username:
        // If you are using FOSUserBundle:
        $user_manager = $this->get('fos_user.user_manager');
        $user = $user_manager->findUserByUsername($_username);
        // Or by yourself
        $user = $this->getDoctrine()->getManager()->getRepository("userBundle:User")
                ->findOneBy(array('username' => $_username));
        /// End Retrieve user

        // Check if the user exists !
        if(!$user){
            return new Response(
                'Username doesnt exists', Response::HTTP_UNAUTHORIZED, array('Content-type' => 'application/json')
            );
        }

        /// Start verification
        $encoder = $factory->getEncoder($user);
        $salt = $user->getSalt();

        if(!$encoder->isPasswordValid($user->getPassword(), $_password, $salt)) {
            return new Response(
                'Username or Password not valid.', Response::HTTP_UNAUTHORIZED, array('Content-type' => 'application/json')
            );
        } 
        /// End Verification

        // The password matches ! then proceed to set the user in session
        
        //Handle getting or creating the user entity likely with a posted form
        // The third parameter "main" can change according to the name of your firewall in security.yml
        $token = new UsernamePasswordToken($user, null, 'main', $user->getRoles());
        $this->get('security.token_storage')->setToken($token);

        // If the firewall name is not main, then the set value would be instead:
        // $this->get('session')->set('_security_XXXFIREWALLNAMEXXX', serialize($token));
        $this->get('session')->set('_security_main', serialize($token));
        
        // Fire the login event manually
        $event = new InteractiveLoginEvent($request, $token);
        $this->get("event_dispatcher")->dispatch("security.interactive_login", $event);
        
        /*
         * Now the user is authenticated !!!! 
         * Do what you need to do now, like render a view, redirect to route etc.
         */
        return new Response(
            'Welcome '. $user->getUsername(), Response::HTTP_OK, array('Content-type' => 'application/json')
        );
    }
}

编码愉快!

赞(0)
未经允许不得转载:srcmini » 如何在Symfony 3上的控制器(带有或不带有FOSUserBundle)中手动验证(登录)用户

评论 抢沙发

评论前必须登录!