用户认证与授权:在 Symfony 中实现安全控制

用户认证与授权:在 Symfony 中实现安全控制

Symfony 是一个功能强大且高度可扩展的 PHP 框架,广泛用于开发复杂的 Web 应用程序。在现代 Web 应用程序中,用户认证和授权是不可或缺的功能,用于确保应用程序的安全性和数据的隐私性。本文将详细介绍如何在 Symfony 中实现用户认证和授权,具体到源码示例,帮助您全面掌握这一重要技能。

一、项目初始化

首先,我们需要创建一个 Symfony 项目。如果您还没有安装 Symfony,可以使用以下命令进行安装:

composer create-project symfony/skeleton my_project
cd my_project

接下来,安装用于用户认证和授权的必要包:

composer require symfony/security-bundle
composer require symfony/orm-pack
composer require symfony/maker-bundle --dev

二、创建用户实体

在 Symfony 中,用户实体通常用来表示应用程序中的用户。我们可以使用 maker-bundle 快速生成用户实体:

php bin/console make:user

按照提示输入必要的信息,例如用户类名 User,是否需要存储密码等。生成的用户实体类如下:

<?phpnamespace App\Entity;use App\Repository\UserRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\UserInterface;#[ORM\Entity(repositoryClass: UserRepository::class)]
class User implements UserInterface, PasswordAuthenticatedUserInterface
{#[ORM\Id]#[ORM\GeneratedValue]#[ORM\Column(type: 'integer')]private $id;#[ORM\Column(type: 'string', length: 180, unique: true)]private $email;#[ORM\Column(type: 'json')]private $roles = [];#[ORM\Column(type: 'string')]private $password;public function getId(): ?int{return $id;}public function getEmail(): ?string{return $email;}public function setEmail(string $email): self{$this->email = $email;return $this;}/*** A visual identifier that represents this user.** @see UserInterface*/public function getUserIdentifier(): string{return (string) $this->email;}/*** @see UserInterface*/public function getRoles(): array{$roles = $this->roles;// guarantee every user at least has ROLE_USER$roles[] = 'ROLE_USER';return array_unique($roles);}public function setRoles(array $roles): self{$this->roles = $roles;return $this;}/*** @see PasswordAuthenticatedUserInterface*/public function getPassword(): string{return $this->password;}public function setPassword(string $password): self{$this->password = $password;return $this;}/*** @see UserInterface*/public function eraseCredentials(){// If you store any temporary, sensitive data on the user, clear it here// $this->plainPassword = null;}
}

三、数据库配置与迁移

接下来,我们需要配置数据库连接并进行迁移。首先,在 .env 文件中配置数据库连接信息:

DATABASE_URL="mysql://db_user:db_password@127.0.0.1:3306/db_name"

然后,运行以下命令以创建数据库和迁移用户实体:

php bin/console doctrine:database:create
php bin/console make:migration
php bin/console doctrine:migrations:migrate

四、实现用户注册功能

用户注册功能允许新用户在应用程序中创建账户。首先,我们需要创建一个注册表单。使用以下命令生成表单:

php bin/console make:registration-form

按照提示选择生成表单所需的选项。生成的表单类如下:

<?phpnamespace App\Form;use App\Entity\User;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\Length;class RegistrationFormType extends AbstractType
{public function buildForm(FormBuilderInterface $builder, array $options): void{$builder->add('email', EmailType::class)->add('plainPassword', RepeatedType::class, ['type' => PasswordType::class,'first_options' => ['label' => 'Password'],'second_options' => ['label' => 'Repeat Password'],'invalid_message' => 'The password fields must match.','options' => ['attr' => ['class' => 'password-field']],'required' => true,'mapped' => false,'constraints' => [new NotBlank(['message' => 'Please enter a password',]),new Length(['min' => 6,'minMessage' => 'Your password should be at least {{ limit }} characters','max' => 4096,]),],]);}public function configureOptions(OptionsResolver $resolver): void{$resolver->setDefaults(['data_class' => User::class,]);}
}

接下来,创建一个控制器来处理用户注册请求:

<?phpnamespace App\Controller;use App\Entity\User;
use App\Form\RegistrationFormType;
use App\Security\LoginFormAuthenticator;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Authentication\UserAuthenticatorInterface;class RegistrationController extends AbstractController
{#[Route('/register', name: 'app_register')]public function register(Request $request, UserPasswordHasherInterface $userPasswordHasher, UserAuthenticatorInterface $userAuthenticator, LoginFormAuthenticator $authenticator, EntityManagerInterface $entityManager): Response{$user = new User();$form = $this->createForm(RegistrationFormType::class, $user);$form->handleRequest($request);if ($form->isSubmitted() && $form->isValid()) {// encode the plain password$user->setPassword($userPasswordHasher->hashPassword($user,$form->get('plainPassword')->getData()));$entityManager->persist($user);$entityManager->flush();// do anything else you need here, like send an emailreturn $userAuthenticator->authenticateUser($user,$authenticator,$request);}return $this->render('registration/register.html.twig', ['registrationForm' => $form->createView(),]);}
}

创建注册页面模板 templates/registration/register.html.twig

{% extends 'base.html.twig' %}{% block body %}
<h1>Register</h1>{{ form_start(registrationForm) }}{{ form_widget(registrationForm) }}<button type="submit" class="btn">Register</button>
{{ form_end(registrationForm) }}
{% endblock %}

五、实现用户登录功能

用户登录功能允许已注册用户访问受保护的资源。首先,使用以下命令生成登录表单:

php bin/console make:auth

按照提示选择 Login form authenticator 选项并提供必要的信息。生成的 LoginFormAuthenticator 类如下:

<?phpnamespace App\Security;use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticator;
use Symfony\Component\Security\Http\Util\TargetPathTrait;class LoginFormAuthenticator extends AbstractFormLoginAuthenticator
{use TargetPathTrait;private RouterInterface $router;public function __construct(RouterInterface $router){$this->router = $router;}public function supports(Request $request): bool{return 'app_login' === $request->attributes->get('_route') && $request->isMethod('POST');}public function getCredentials(Request $request){$credentials = ['email' => $request->request->get('email'),'password' => $request->request->get('password'),];$request->getSession()->set(Security::LAST_USERNAME, $credentials['email']);return $credentials;}public function getUser($credentials, UserProviderInterface $userProvider): ?UserInterface{return $userProvider->loadUserByUsername($credentials['email']);}public function checkCredentials($credentials, UserInterface $user): bool{// Check the user's password, return true if it's valid// For example:// return $this->passwordEncoder->isPasswordValid($user, $credentials['password']);return true;}public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $providerKey): ?RedirectResponse{if ($targetPath = $this->getTargetPath($request->getSession(), $providerKey)) {return new RedirectResponse($targetPath);}return new RedirectResponse($this->router->generate('homepage'));}protected function getLoginUrl(): string{return $this->router->generate('app_login');}
}

接下来,创建一个控制器来处理登录请求:

<?phpnamespace App\Controller;use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;class SecurityController extends AbstractController
{#[Route('/login', name: 'app_login')]public function login(AuthenticationUtils $authenticationUtils): Response{// get the login error if there is one$error = $authenticationUtils->getLastAuthenticationError();// last username entered by the user$lastUsername = $authenticationUtils->getLastUsername();return $this->render('security/login.html.twig', ['last_username' => $lastUsername, 'error' => $error]);}#[Route('/logout', name: 'app_logout')]public function logout(): void{throw new \Exception('This method can be blank - it will be intercepted by the logout key on your firewall');}
}

创建登录页面模板 templates/security/login.html.twig

{% extends 'base.html.twig' %}{% block body %}
<h1>Login</h1><form action="{{ path('app_login') }}" method="post"><label for="email">Email:</label><input type="text" id="email" name="_username" value="{{ last_username }}" required autofocus><label for="password">Password:</label><input type="password" id="password" name="_password" required><button type="submit">Login</button>{% if error %}<div>{{ error.messageKey|trans(error.messageData, 'security') }}</div>{% endif %}
</form>
{% endblock %}

六、配置安全策略

为了保护应用程序的某些部分,我们需要配置安全策略。在 config/packages/security.yaml 文件中进行以下配置:

security:encoders:App\Entity\User:algorithm: autoproviders:app_user_provider:entity:class: App\Entity\Userproperty: emailfirewalls:dev:pattern: ^/(_(profiler|wdt)|css|images|js)/security: falsemain:anonymous: truelazy: trueprovider: app_user_providerform_login:login_path: app_logincheck_path: app_logincsrf_token_generator: security.csrf.token_managerlogout:path: app_logouttarget: /access_control:- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }- { path: ^/register, roles: IS_AUTHENTICATED_ANONYMOUSLY }- { path: ^/, roles: ROLE_USER }

七、实现角色授权

在许多应用程序中,用户的权限根据其角色而不同。我们可以在用户实体中定义角色,并在控制器中根据角色进行授权。例如:

<?phpnamespace App\Controller;use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;class AdminController extends AbstractController
{#[Route('/admin', name: 'admin')]#[IsGranted('ROLE_ADMIN')]public function index(): Response{return new Response('Admin area');}
}

在上述示例中,只有具有 ROLE_ADMIN 角色的用户才能访问 /admin 路由。

八、保护特定资源

您可以使用注释来保护特定的控制器方法。例如:

<?phpnamespace App\Controller;use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;class AccountController extends AbstractController
{#[Route('/account', name: 'account')]#[IsGranted('ROLE_USER')]public function index(): Response{return new Response('Account area');}
}

在上述示例中,只有具有 ROLE_USER 角色的用户才能访问 /account 路由。

九、总结

本文详细介绍了在 Symfony 中实现用户认证与授权的全过程。从项目初始化、创建用户实体、配置数据库、实现用户注册和登录功能,到配置安全策略和实现角色授权,涵盖了每个步骤的具体代码和配置示例。通过这些示例,您可以全面掌握在 Symfony 中实现安全控制的技巧,为构建安全的 Web 应用程序奠定坚实的基础。

希望本文能对您有所帮助,如果您有任何问题或需要进一步的帮助,请随时与我联系。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/386691.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【全志H616开发】Linux守护进程

文章目录 守护进程简介基本特点创建一个守护进程通常涉及以下步骤&#xff1a;进程查看指令&#xff1a; 守护进程开发代码示例&#xff1a; 开机自动启动 守护进程 简介 Linux Daemon&#xff08;守护进程&#xff09;是运行在后台的一种特殊进程。它独立于控制终端并且周期性…

VScode | 我的常用插件分享

系列文章目录 本系列文章主要分享作位前端开发的工具之------VScode的使用分享。 文章目录 目录 系列文章目录 文章目录 前言 一、Vetur 三、别名路径跳转 四、Prettier 五、koroFileHeader 六、vue-helper 总结 前言 本文主要分享VScode的好用插件。 一、Vetur Vue的Vetur插…

【Vulnhub系列】Vulnhub_Raven2靶场渗透(原创)

【Vulnhub系列靶场】Vulnhub_Raven2 渗透 原文转载已经过授权 原文链接&#xff1a;Lusen的小窝 - 学无止尽&#xff0c;不进则退 (lusensec.github.io) 一、环境准备 从网盘下载该靶机&#xff0c;在vm中选择【打开】 然后设置好存储路径&#xff0c;开机后检查靶机的网络连…

谷粒商城实战笔记-84-商品服务-API-新增商品-获取分类关联的品牌

文章目录 一&#xff0c;品牌查询接口的后台实现二&#xff0c;编码经验总结1&#xff0c;Controller层的作用1.1 参数处理1.2 调用Service1.3 处理Service返回结果实例 2&#xff0c;VO的封装时机3&#xff0c;Service中最好注入Service&#xff0c;不要直接依赖Dao 问题记录 …

vue2 vue3 props 的处理机制

在 Vue 2 中&#xff0c;props 是单向数据流&#xff0c;父组件向子组件传递的 props 默认情况下是不具有响应式特性的。这意味着当父组件的数据发生变化时&#xff0c;如果传递给子组件的 props 发生变化&#xff0c;子组件不会自动更新视图。 具体来说&#xff0c;在 Vue 2 …

增量学习中Task incremental、Domain incremental、Class incremental 三种学习模式的概念及代表性数据集?

1 概念 在持续学习领域&#xff0c;Task incremental、Domain incremental、Class incremental 是三种主要的学习模式&#xff0c;它们分别关注不同类型的任务序列和数据分布变化。 1.1 Task Incremental Learning (Task-incremental) 任务增量学习&#xff0c;也称为任务增…

【论文共读】【翻译】【GAN】Generative Adversarial Nets

论文原文地址&#xff1a;https://arxiv.org/pdf/1406.2661 翻译&#xff1a;Generative Adversarial Nets 生成对抗网络 0. 摘要 提出了一种新的对抗过程估计生成模型的框架&#xff0c;其中我们同时训练两个模型&#xff1a;一个是捕获数据分布的生成模型G&#xff0c;另一…

燃气安全无小事,一双专业劳保鞋让你步步安心!

燃气作为我们日常生活中不可或缺的能源之一&#xff0c;为我们的生活提供了极大便利&#xff0c;其安全性往往被忽视在忙碌的日常生活背后。然而&#xff0c;燃气事故一旦发生&#xff0c;后果往往不堪设想&#xff0c;轻则财产损失&#xff0c;重则危及生命。因此&#xff0c;…

dockerfile部署镜像 ->push仓库 ->虚拟机安装建木 ->自动部署化 (详细步骤)

目录 创建私服仓库 vi /etc/docker/daemon.json vim deploy.sh判断脚本内容 创建 建木 后端部署 命名空间 设置密码用户名 创建git仓库 gitignore文件内容 图形项目操作 git maven docker镜像 点击流程日志 vim /etc/docker/daemon.json 执行部署脚本 ip 开发…

Linux网络——深入理解传入层协议TCP

目录 一、前导知识 1.1 TCP协议段格式 1.2 TCP全双工本质 二、三次握手 2.1 标记位 2.2 三次握手 2.3 捎带应答 2.4 标记位 RST 三、四次挥手 3.1 标记位 FIN 四、确认应答(ACK)机制 五、超时重传机制 六 TCP 流量控制 6.1 16位窗口大小 6.2 标记位 PSH 6.3 标记…

Jackson常用注解详解

Hi &#x1f44b;, Im shy 有人见尘埃&#xff0c;有人见星辰 Jackson常用注解详解 文章目录 Jackson常用注解详解0. 引入依赖1. JsonProperty2. JsonIgnore3. JsonFormat4. JsonInclude5. JsonCreator6. JsonValue7. JsonIgnoreProperties结论 Jackson是Java生态系统中广泛…

Redis学习[1] ——基本概念和数据类型

Redis学习[1] ——基本概念和数据类型 一、Redis基础概念 1.1 Redis是什么&#xff0c;有什么特点&#xff1f; Redis是一个基于**内存的数据库&#xff0c;因此读写速度非常快**&#xff0c;常用作缓存、消息队列、分布式锁和键值存储数据库。支持多种数据结构&#xff1a;…

大数据与人工智能:数据隐私与安全的挑战_ai 和 数据隐私

前言 1.背景介绍 随着人工智能(AI)和大数据技术的不断发展&#xff0c;我们的生活、工作和社会都在不断变化。这些技术为我们提供了许多好处&#xff0c;但同时也带来了一系列挑战&#xff0c;其中数据隐私和安全是最为关键的之一。数据隐私和安全问题的出现&#xff0c;主要…

分布式锁的三种实现方式:Redis、基于数据库和Zookeeper

分布式锁的实现 操作共享资源&#xff1a;例如操作数据库中的唯一用户数据、订单系统、优惠券系统、积分系统等&#xff0c;这些系统需要修改用户数据&#xff0c;而多个系统可能同时修改同一份数据&#xff0c;这时就需要使用分布式锁来控制访问&#xff0c;防止数据不一致。…

angular入门基础教程(九)依赖注入(DI)

依赖注入 Angular 中的依赖注入&#xff08;DI&#xff09;是框架最强大的特性之一。可以将依赖注入视为 Angular 在运行时为你的应用 提供所需资源的能力。依赖项可以是服务或其他资源。 使用服务的一种方式是作为与数据和 API 交互的方式。为了使服务可重用&#xff0c;应该…

实战:ZooKeeper 操作命令和集群部署

ZooKeeper 操作命令 ZooKeeper的操作命令主要用于对ZooKeeper服务中的节点进行创建、查看、修改和删除等操作。以下是一些常用的ZooKeeper操作命令及其说明&#xff1a; 一、启动与连接 启动ZooKeeper服务器&#xff1a; ./zkServer.sh start这个命令用于启动ZooKeeper服务器…

SSM学习9:SpringBoot简介、创建项目、配置文件、多环节配置

简介 SpringBoot式用来简化Spring应用的初始搭建以及开发过程的一个框架 项目搭建 File -> New -> Project 选中pom.xml文件&#xff0c;设置为maven项目 项目启动成功 可以访问BasicController中的路径 配置文件 在resources目录下 application.properties 默…

Linux——管理本地用户和组(详细介绍了Linux中用户和组的概念及用法)

目录 一、用户和组概念 &#xff08;一&#xff09;、用户的概念 &#xff08;二&#xff09;、组的概念 补充组 主要组 二、获取超级用户访问权限 &#xff08;一&#xff09;、su 命令和su -命令 &#xff08; 二&#xff09;、sudo命令 三、管理本地用户账户 &…

WPF---Prism视图传参

Prism视图传参方式。 实际应用场景 点击tabitem中的列表数据&#xff0c;同步更新到ListStatic Region对应的界面。目前用两种方式实现了传参数据同步。 第一&#xff0c;事件聚合器&#xff08;EventAggregator&#xff09; 1. 定义事件 创建一个事件类&#xff0c;用于传…

微信小程序配置访问服务器失败所发现的问题及解决方案

目录 事前现象问题1&#xff1a;问题现象&#xff1a;问题分析&#xff1a; 问题2&#xff1a;问题现象&#xff1a;问题分析&#xff1a;解决方案&#xff1a; 事后现象 事前现象 问题1&#xff1a; 问题现象&#xff1a; 在本地调试时&#xff0c;一切顺利&#xff0c;但一…