Laravel安全应用模块示例教程

打印 上一主题 下一主题

主题 821|帖子 821|积分 2463

前言

Laravel 是一个流行的 PHP 框架,它提供了一套丰富的功能来资助开发者构建安全、可维护的应用步伐。下面,我将详细解释 Laravel 中关于认证、CSRF 保护、授权、哈希、加密、密码重置等安全模块的实现逻辑、应用场景以及相应的示例代码。
详情见官方中文文档
一. 认证(Authentication)

Laravel的认证系统是一个强盛且机动的用户身份验证办理方案,它基于PHP的Laravel框架构建。以下是Laravel认证系统的工作流程详细形貌:

1. 用户数据预备



  • 数据表创建:首先,需要有一个用于存储用户信息的数据库表,通常这个表被命名为users。Laravel提供了php artisan make:auth命令,该命令不仅生成认证所需的控制器和视图,还会创建一个默认的users迁徙文件,用于创建这个表。表中通常包含字段如id、name、email、password(哈希处置惩罚后的密码)、remember_token(用于“记着我”功能)等。
  • 迁徙与实行:通过php artisan migrate命令实行迁徙,将users表创建到数据库中。
2. 认证设置



  • 设置文件:Laravel的认证设置位于config/auth.php文件中。这里定义了认证的“guards”和“providers”。Guards定义了用户在每个请求中怎样实现认证(如通过Session或Token),而Providers则定义了怎样从持久化存储中获取用户信息(如通过Eloquent ORM或数据库查询构造器)。
  • 默认设置:Laravel通常使用默认的web guard和users provider。这意味着Laravel会通过Session来维护用户的认证状态,并通过Eloquent ORM从users表中检索用户信息。
3. 认证流程



  • 用户登录

    • 用户访问登录页面,输入用户名(或邮箱)和密码。
    • 提交表单后,请求被发送到登录路由(如/login),该路由由Laravel的认证控制器(通常是LoginController)处置惩罚。
    • 控制器验证用户名和密码的正确性。这通常涉及将用户输入的密码进行哈希处置惩罚,并与数据库中存储的哈希值进行比较。
    • 如果验证成功,Laravel将用户的认证信息存储到Session中,并可能生成一个remember_token(如果用户勾选了“记着我”选项)。
    • 用户被重定向到登录成功后的页面(通常是首页或某个受保护的页面)。

  • 用户注销

    • 用户访问注销页面或点击注销链接。
    • 注销请求被发送到注销路由(如/logout),该路由由Laravel的认证控制器处置惩罚。
    • 控制器销毁Session中的认证信息,并可能删除remember_token。
    • 用户被重定向到登录页面或其他指定的页面。

4. 认证状态检查



  • Laravel提供了多种方式来检查用户的认证状态,如使用Auth门面或Illuminate\Http\Request实例的user()方法。
  • 中间件(如auth中间件)可以在路由定义中使用,以限定只有认证用户才能访问特定路由或控制器。
5. 密码重置



  • Laravel还提供了密码重置功能,允许用户通过邮箱重置密码。
  • 用户提交密码重置请求后,系统会向用户的注册邮箱发送一封包含重置密码链接的邮件。
  • 用户点击链接后,可以输入新密码来重置密码。
6. 自定义认证



  • Laravel的认证系统非常机动,允许开发者根据需要自定义认证逻辑。
  • 开发者可以定义自己的认证Guard和Provider,甚至完全重写认证流程。
总的来说,Laravel的认证系统通过结合Session、Eloquent ORM、路由、中间件和视图等技术,提供了一个既安全又易于使用的用户身份验证办理方案。
示例代码
  1. # 安装 Laravel UI
  2. composer require laravel/ui
  3. php artisan ui vue --auth
  4. php artisan migrate
复制代码
这会自动生成登录、注册等视图和路由。
二. CSRF 保护

Laravel的CSRF(跨站请求伪造)系统是一种安全措施,用于保护Web应用步伐免受恶意请求的攻击。以下是Laravel CSRF系统的工作流程详细形貌:
1. CSRF令牌生成



  • 初次访问:当用户初次访问Laravel应用步伐时,Laravel会自动为每个用户会话生成一个唯一的CSRF令牌。这个令牌是一个包含随机字符串的加密值,用于验证后续请求的合法性。
  • 令牌存储:生成的CSRF令牌被存储在用户的会话中(通常是基于服务器的会话存储机制,如Redis或文件会话驱动)。同时,Laravel也提供了一个辅助函数csrf_token(),用于在需要时获取当前会话的CSRF令牌值。
2. CSRF令牌通报



  • 表单提交:在Laravel中,当使用Blade模板引擎创建表单时,可以通过在表单中添加@csrf Blade指令来自动包含CSRF令牌。这个指令会被Laravel剖析为一个隐藏的<input>字段,字段的name属性通常为_token,value属性为当前会话的CSRF令牌值。如许,当用户提交表单时,CSRF令牌会被包含在请求中发送给服务器。
  • Ajax请求:对于Ajax请求,开发者需要在请求头(通常是X-CSRF-TOKEN)中手动设置CSRF令牌。这可以通过从meta标签或JavaScript变量中获取CSRF令牌值来实现。
3. CSRF令牌验证



  • 中间件验证:Laravel提供了一个名为VerifyCsrfToken的中间件,用于自动验证全部传入的POST、PUT、PATCH和DELETE请求中的CSRF令牌。这个中间件是全局中间件组($middlewareGroups数组中的web中间件组)的一部分,因此默认环境下,全部通过Web路由(定义在routes/web.php文件中的路由)的请求都会颠末CSRF验证。
  • 验证过程:当请求到达VerifyCsrfToken中间件时,它会检查请求中是否包含CSRF令牌,而且该令牌是否与会话中存储的令牌相匹配。如果令牌有效,请求将继续被处置惩罚;如果令牌无效或缺失,中间件将拒绝请求,并通常返回一个HTTP 419状态码(表示CSRF令牌不匹配)。
4. 清除特定路由



  • 在某些环境下,开发者可能盼望清除某些路由或控制器方法的CSRF验证。这可以通过在VerifyCsrfToken中间件的$except属性中添加这些路由的URI或控制器方法名来实现。如许,这些路由或方法将不会受到CSRF验证的影响。
5. 自定义CSRF验证



  • Laravel的CSRF系统虽然非常强盛且易于使用,但开发者仍旧可以根据需要自定义CSRF验证逻辑。这可以通过扩展VerifyCsrfToken中间件、创建自定义中间件或直接在控制器中处置惩罚CSRF验证来实现。
示例代码
在表单中自动包含 CSRF 令牌:
  1. <form method="POST" action="/profile">
  2.     @csrf
  3.     <!-- 表单内容 -->
  4. </form>
复制代码
三. 授权(Authorization)

Laravel的授权系统是一个复杂但机动的机制,它允许开发者控制用户对应用步伐中资源的访问权限。这个系统通常与Laravel的认证系统精麋集成,但它是独立的,可以单独使用。下面我将详细形貌Laravel授权系统的工作方式,并给出详细的示例代码。

1. 授权系统概述

Laravel的授权系统主要依赖于以下几个组件:

  • 计谋(Policies):计谋提供了一种将授权逻辑构造到单个类中的方法。每个模子(如Post、User等)都可以有一个对应的计谋类,该类定义了哪些用户可以对模子实行哪些操作(如检察、创建、更新、删除等)。
  • 门面(Gates):门面提供了一种定义授权逻辑的方式,这些逻辑不直接关联到特定的模子。它们更适合于更通用的权限检查,如检查用户是否是管理员。
  • 中间件:虽然中间件自己不直接用于授权,但它们可以在请求处置惩罚之前检查用户是否具备访问特定资源的权限,并根据检查效果允许或拒绝请求。
2. 计谋(Policies)

假设我们有一个Post模子,并盼望控制哪些用户可以检察、编辑或删除帖子。我们可以为Post模子创建一个计谋类。
首先,使用Artisan命令生成计谋:
  1. php artisan make:policy PostPolicy
复制代码
然后,在生成的PostPolicy类中定义授权方法:
  1. namespace App\Policies;
  2. use App\Models\Post;
  3. use App\Models\User;
  4. use Illuminate\Auth\Access\HandlesAuthorization;
  5. class PostPolicy
  6. {
  7.     use HandlesAuthorization;
  8.     /**
  9.      * 确定用户是否可以查看帖子。
  10.      *
  11.      * @param  \App\Models\User  $user
  12.      * @param  \App\Models\Post  $post
  13.      * @return mixed
  14.      */
  15.     public function view(User $user, Post $post)
  16.     {
  17.         // 示例:所有人都可以查看帖子
  18.         return true;
  19.         // 或者,你可以添加更复杂的逻辑来检查用户是否有权查看帖子
  20.         // 例如:return $user->id === $post->user_id;
  21.     }
  22.     /**
  23.      * 确定用户是否可以更新帖子。
  24.      *
  25.      * @param  \App\Models\User  $user
  26.      * @param  \App\Models\Post  $post
  27.      * @return mixed
  28.      */
  29.     public function update(User $user, Post $post)
  30.     {
  31.         // 示例:只有帖子的创建者可以更新帖子
  32.         return $user->id === $post->user_id;
  33.     }
  34.     // ... 其他方法,如 delete, create 等
  35. }
复制代码
接下来,在AuthServiceProvider中注册计谋:
  1. namespace App\Providers;
  2. use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
  3. use Illuminate\Support\Facades\Gate;
  4. class AuthServiceProvider extends ServiceProvider
  5. {
  6.     protected $policies = [
  7.         'App\Models\Post' => 'App\Policies\PostPolicy',
  8.         // ... 其他模型与策略的映射
  9.     ];
  10.     // ... 其他代码
  11. }
复制代码
现在,你可以在控制器或视图中使用auth()->user()->can('update', $post)来检查当前用户是否可以更新给定的帖子。Laravel会自动剖析update操作到PostPolicy的update方法。
3. 门面(Gates)

如果你需要定义不直接关联到模子的授权逻辑,可以使用门面。在AuthServiceProvider的boot方法中定义门面:
  1. public function boot()
  2. {
  3.     $this->registerPolicies();
  4.     Gate::define('is-admin', function ($user) {
  5.         return $user->is_admin;
  6.     });
  7.     // ... 其他门面定义
  8. }
复制代码
然后,你可以使用auth()->user()->can('is-admin')来检查当前用户是否是管理员。
4. 示例代码

在控制器中使用计谋:
  1. namespace App\Http\Controllers;
  2. use App\Models\Post;
  3. use Illuminate\Http\Request;
  4. class PostController extends Controller
  5. {
  6.     public function update(Request $request, Post $post)
  7.     {
  8.         if (!auth()->user()->can('update', $post)) {
  9.             abort(403, 'Unauthorized action.');
  10.         }
  11.         // 更新帖子的逻辑...
  12.     }
  13. }
复制代码
在控制器中使用门面:
  1. namespace App\Http\Controllers;
  2. use Illuminate\Http\Request;
  3. class AdminController extends Controller
  4. {
  5.     public function dashboard()
  6.     {
  7.         if (!auth()->user()->can('is-admin')) {
  8.             abort(403, 'Access denied.');
  9.         }
  10.         // 显示管理员仪表板的逻辑...
  11.     }
  12. }
复制代码
如许,Laravel的授权系统就允许你以机动且构造良好的方式控制用户对应用步伐中资源的访问权限。
四. 哈希(Hashing)

Laravel的哈希系统提供了一种安全的方式来存储用户密码,确保这些密码在数据库中以加密的形式存在,即使数据库被泄漏,攻击者也无法直接获取到用户的原始密码。Laravel使用Bcrypt算法作为默认的哈希方法,这是一种基于Blowfish密码算法的密码散列函数,被认为是安全且高效的。

1. 哈希系统的工作原理


  • 密码加密:当用户注册或更改密码时,Laravel会接收用户输入的密码,并使用Bcrypt算法对其进行哈希处置惩罚。这个过程包括多次迭代(默认是10次,但Laravel允许你自定义迭代次数以进步安全性)和添加盐值(salt),以确保即使两个用户有相同的密码,它们存储在数据库中的哈希值也会不同。
  • 密码验证:当用户登录时,Laravel会接收用户输入的密码,并使用相同的Bcrypt算法(包括相同的迭代次数和盐值)对其进行哈希处置惩罚。然后,Laravel会比较这个新生成的哈希值与数据库中存储的哈希值。如果它们匹配,阐明用户输入的密码是正确的;如果不匹配,则密码错误。
2. 示例代码

在Laravel中,你通常不需要直接调用哈希函数来处置惩罚密码,由于Laravel的认证系统(如Laravel Breeze、Laravel Jetstream或Laravel Fortify)已经为你处置惩罚了这些逻辑。但是,为了阐明怎样手动使用Laravel的哈希系统,我们可以看一些示例代码。


  • 加密密码:在注册用户时,你可能需要加密用户的密码并将其存储在数据库中。你可以使用Hash门面来做到这一点:
  1. use Illuminate\Support\Facades\Hash;
  2. // 假设$request是一个包含用户输入的请求对象
  3. $password = $request->input('password');
  4. // 使用Bcrypt算法加密密码
  5. $hashedPassword = Hash::make($password);
  6. // 现在,你可以将$hashedPassword存储在数据库中
  7. // ...
复制代码


  • 验证密码:在用户登录时,你需要验证用户输入的密码是否与数据库中存储的哈希值匹配。你仍旧可以使用Hash门面来做到这一点:
  1. use Illuminate\Support\Facades\Hash;
  2. // 假设$user是一个用户模型实例,它有一个`password`属性
  3. // 并且$password是用户登录时输入的密码
  4. // 验证密码
  5. if (Hash::check($password, $user->password)) {
  6.     // 密码匹配,用户登录成功
  7.     // ...
  8. } else {
  9.     // 密码不匹配,用户登录失败
  10.     // ...
  11. }
复制代码
3. 留意事项



  • 永久不要在数据库中存储用户的原始密码。
  • 当用户更改密码时,总是使用Hash::make()来生成新的哈希值,由于每次调用都会生成一个唯一的盐值。
  • Laravel的哈希系统足够安全,用于大多数应用步伐场景。但是,如果你有特殊的安全需求,你可以考虑使用更高级的哈希算法或设置。
  • Laravel的认证系统(如Laravel Breeze、Laravel Jetstream等)已经内置了对密码哈希的支持,因此,在大多数环境下,你不需要直接调用哈希函数。这些系统提供了用户注册、登录、密码重置等功能的完备实现。
五. 加密(Encryption)

Laravel的加密系统提供了一种方法来保护敏感数据,使其在存储或传输过程中保持私密性。与哈希系统不同,加密系统是可逆的,意味着加密后的数据可以被解密回其原始形式。Laravel使用对称加密(如AES)和非对称加密(如RSA)技术,但默认环境下,它使用OpenSSL库和AES-256-CBC加密算法来加密和解密数据。

1. 加密系统的工作原理



  • 生成密钥:Laravel加密系统依赖于一个加密密钥(通常位于.env文件中的APP_KEY)。这个密钥用于加密和解密数据。出于安全考虑,这个密钥应该保持私密,而且不应该硬编码在源代码中。
  • 加密数据:当你想要加密数据时,Laravel会使用加密密钥和加密算法(如AES-256-CBC)对数据进行加密。加密过程还会生成一个初始化向量(IV),该向量是随机生成的,并与加密后的数据一起存储或传输。IV是公开的,但每个加密过程都应使用不同的IV来增长安全性。
  • 解密数据:当需要解密数据时,Laravel会使用相同的加密密钥、加密算法和与加密数据一起存储或传输的IV来解密数据。如果密钥、算法和IV都匹配,数据将被成功解密回其原始形式。
2. 示例代码

在Laravel中,你可以使用Crypt门面来加密和解密数据。
加密数据

  1. use Illuminate\Support\Facades\Crypt;
  2. // 假设$data是你想要加密的敏感数据
  3. $data = 'This is a secret message.';
  4. // 加密数据
  5. $encryptedData = Crypt::encryptString($data);
  6. // 现在,$encryptedData包含了加密后的数据,你可以安全地将其存储在数据库中
  7. // ...
复制代码
留意:在Laravel 8.x及更高版本中,推荐使用encryptString方法来加密字符串,由于它会自动处置惩罚序列化过程(如果需要的话)。在较旧的Laravel版本中,你可能需要使用encrypt方法,但请留意,encrypt方法接受数组并自动序列化它们,因此你可能需要在解密后使用unserialize(如果加密的是数组的话)。
解密数据

  1. use Illuminate\Support\Facades\Crypt;
  2. // 假设$encryptedData是你从数据库中检索到的加密数据
  3. // 解密数据
  4. $decryptedData = Crypt::decryptString($encryptedData);
  5. // 现在,$decryptedData包含了原始的敏感数据
  6. // ...
复制代码
同样,留意在Laravel 8.x及更高版本中使用decryptString方法来解密字符串。在较旧的版本中,你可能需要使用decrypt方法,但请确保你处置惩罚的是正确范例的数据(例如,如果加密的是数组,解密后可能需要unserialize)。
3. 留意事项



  • 永久不要更改.env文件中的APP_KEY,除非你已经预备好重新加密全部现有的加密数据,由于这将导致你无法解密使用旧密钥加密的数据。
  • 当处置惩罚加密数据时,请确保你相识你正在加密的数据范例(字符串、数组等),以便在解密后正确处置惩罚它们。
  • Laravel的加密系统非常强盛且安全,但请记着,它不应该用于验证用户输入的密码(例如,在登录过程中)。对于密码,你应该使用Laravel的哈希系统。
六. 密码重置

Laravel的密码重置功能是一个强盛的特性,允许用户通过电子邮件重置他们忘记的密码。这个功能依赖于Laravel的认证系统,特殊是Laravel Breeze、Laravel Jetstream或Laravel Fortify等认证脚手架,它们为密码重置流程提供了完备的实现。不过,我们可以概述一下密码重置功能的基本工作流程,并给出一个简化的示例来阐明它是怎样工作的。

密码重置工作流程


  • 用户请求密码重置

    • 用户访问登录页面并点击“忘记密码”链接。
    • 用户被重定向到一个密码重置表单,要求他们输入他们的电子邮件地址。
    • 用户提交表单,Laravel会验证电子邮件地址是否存在于数据库中。

  • 发送密码重置链接

    • 如果电子邮件地址有效,Laravel会生成一个一次性令牌(token),并将其与用户的电子邮件地址关联起来存储在数据库中(通常是暂时表或用户的某个字段中)。
    • Laravel使用邮件服务发送一封包含密码重置链接的电子邮件给用户。这个链接通常包含用户的电子邮件地址和一次性令牌作为查询参数。

  • 用户重置密码

    • 用户点击电子邮件中的链接,被重定向到密码重置表单页面。
    • 表单中预添补了用户的电子邮件地址(可选),并要求用户输入新密码和确认新密码。
    • 用户提交表单,Laravel验证新密码的复杂性,并使用一次性令牌来验证请求的合法性。
    • 如果验证通过,Laravel会更新用户的密码,并可能删除或标记一次性令牌为已使用。

  • 完成密码重置

    • Laravel通常会向用户表现一条消息,表明他们的密码已成功重置。
    • 用户现在可以使用新密码登录到他们的账户。

示例代码(简化)

请留意,以下示例代码是高度简化的,而且不会直接运行在一个Laravel应用步伐中,由于它省略了许多紧张的细节,如验证、错误处置惩罚和Laravel的内置密码重置路由和控制器。但是,它可以资助你理解密码重置流程的基本思想。
  1. // 假设这是处理密码重置请求的逻辑的一部分
  2. // 1. 用户提交电子邮件地址以请求密码重置
  3. // 这里我们假设已经验证了电子邮件地址并发送了包含令牌的电子邮件
  4. // 2. 用户点击电子邮件中的链接,被重定向到密码重置表单
  5. // 表单处理逻辑(通常是一个POST请求)
  6. public function resetPassword(Request $request)
  7. {
  8.     $request->validate([
  9.         'email' => 'required|email',
  10.         'password' => 'required|confirmed|min:8',
  11.         'token' => 'required'
  12.     ]);
  13.     // 查找与电子邮件和令牌匹配的用户
  14.     $user = User::where('email', $request->email)->where('reset_token', $request->token)->first();
  15.     if (!$user || $user->reset_token_expired()) {
  16.         // 令牌无效或已过期
  17.         return back()->withErrors(['token' => '无效的令牌或链接已过期。']);
  18.     }
  19.     // 更新用户的密码
  20.     $user->password = Hash::make($request->password);
  21.     $user->reset_token = null; // 重置令牌(可选,取决于你的实现)
  22.     $user->save();
  23.     // 密码重置成功
  24.     Auth::login($user); // 可选:自动登录用户
  25.     return redirect('/')->with('success', '密码已成功重置!');
  26. }
  27. // 注意:上面的代码示例中省略了许多重要的细节,
  28. // 如`reset_token`和`reset_token_expired`方法的实现,
  29. // 以及发送密码重置电子邮件的逻辑。
  30. // 在实际应用中,你应该使用Laravel的内置功能来处理这些任务。
复制代码
在真实的Laravel应用步伐中,密码重置功能通常是通过Laravel的认证脚手架(如Laravel Breeze、Laravel Jetstream)自动设置的,它们提供了路由、控制器、视图和邮件模板来处置惩罚密码重置流程。你不需要从头开始编写这些代码,而是可以使用Laravel提供的这些工具来快速实现密码重置功能。
总结

Laravel的授权系统通过角色、权限和关联关系的定义,以及中间件、计谋和门面的使用,为开发者提供了一个强盛且机动的授权机制。开发者可以根据应用步伐的需求自定义授权逻辑,并确保只有具备相应权限的用户才能访问特定资源。这种机制有助于保护应用步伐的安全性,并提升用户体验。说句题外话,Laravel虽然好用,但是请不要过度依赖,我们还是要去自行理解或者实践开发类似的安全套件,否则开发十年最后还是只会增编削查,那就不好了,感谢各位看到最后,谢谢

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

傲渊山岳

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表