Laravel 提供了一整套身分验证相关的功能,并且当我们安装 Breeze 的时候就已经帮我们实作了大部分机能,不过为了客制或调整其中的功能,还是来了解一下运作的机制。
Auth Facade 帮助快速取用验证的相关功能,包含登入登出等等。这边先介绍直接使用这些功能的方法,底下再来解说背後的机制。
当使用者试图登入的时候,在请求中带上验证身分所需的栏位值,在 Laravel 中预设的就是 email , password 。
/app/Http/Requests/Auth/LoginRequest.php
public function rules()
{
return [
'email' => ['required', 'string', 'email'],
'password' => ['required', 'string'],
];
}
这边还没介绍过资料检查( Validation )的功能,不过上面的程序码应该很好理解,email 跟 password 都是必须( required )栏位。
取得必须的栏位值之後就能用 Auth::attempt 进行检查。
/app/Http/Requests/Auth/LoginRequest.php
use Illuminate\Support\Facades\Auth;
//...
public function authenticate()
{
$this->ensureIsNotRateLimited();
// 如果 attempt 检查失败的话就抛出错误
if (! Auth::attempt($this->only('email', 'password'), $this->boolean('remember'))) {
RateLimiter::hit($this->throttleKey());
throw ValidationException::withMessages([
'email' => __('auth.failed'),
]);
}
RateLimiter::clear($this->throttleKey());
}
Auth::attempt 的第一个参数是要验证的资料阵列,写得直接点的话会像
Auth::attempt([
'email' => 'your_email',
'password' => 'your_password'
]);
第二个参数则用於指定是否要记忆这个使用者,该值为 true 的话就记忆。
Auth::attempt([
'email' => 'your_email',
'password' => 'your_password'
],
$rememberMe
);
而记忆的方式则是在 user 的 remember_token 栏位存入 token ,之後使用者用网页请求时就会用 cookie 内的资讯来对照这个 token 确认是否让使用者快速登入。而当使用者登出的时候这个栏位就会清空,帮助防止 cookie 被劫持的安全问题 。
为了验证身分所必须的栏位其实只有 password ,除 password 外添加的栏位都是用来检索使用者,这些额外的栏位会应用於 where 的搜寻,只有被搜寻到的使用者会进行密码验证。
// 信箱相符且被启用(active)的用户才进行密码验证
if (Auth::attempt(['email' => $email, 'password' => $password, 'active' => 1])) {
}
Auth::attempt 仅用於判定登入资讯是否正确,判定後是要导向首页或是使用者原本尝试拜访的页面、产生 session id 等行为都是另外定义的。
if (Auth::attempt(['email' => $email, 'password' => $password])) {
$request->session()->regenerate();
return redirect()->intended(RouteServiceProvider::HOME);
}
那如果使用者才刚申请完帐号怎麽办呢? 如果是在已经有 User 实例的情况下,可以直接用 login 方法指定该 User 为目前登入的使用者,并更新 session 。
/app/Http/Controllers/Auth/RegisteredUserController.php
public function store(Request $request)
{
$request->validate([
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => ['required', 'confirmed', Rules\Password::defaults()],
]);
$user = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password),
]);
$user->setting()->create();
event(new Registered($user));
Auth::login($user); // 指定新申请的用户为登入的 user
return redirect(RouteServiceProvider::HOME);
}
跟 attempt 一样,可以指定是否记忆使用者
Auth::login($user,$remeberMe);
使用 Auth::logout() 能将更新 user session ,移除其中的登入资讯。
不过官方建议除了登出外也要完全清除 session 资讯,并且重产 csrf_token。
public function logout(Request $request)
{
Auth::logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
return redirect('/');
}
Laravel 的身分验证主要有两个设定, guards 跟 providers
跟身分验证有关的系统设定都在 config/auth.php 中。
首先可以找到 providers 的资料。
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
],
providers 可以理解为发行身分证的来源,主要就是指定要去哪里取得身分相关的资料,像这边定义 users 使用 eloquent 来查询 App\Models\User 的资料,并利用查询出的资料进行身分验证。我们也可追加不同的身分发行类别。
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
'admins' => [
'driver' => 'eloquent',
'model' => App\Models\Admin::class,
],
],
用在这边的 model 需要经过特殊处理,需要有对应的栏位好进行身分验证,最直接的方法就是继承框架的 User Model
<?php
use Illuminate\Foundation\Auth\User as Authenticatable;
class Admin extends Authenticatable
{
//...
}
再打开 Illuminate\Foundation\Auth\User 可以看到也是很多介面或属性的组合,可以参考来自制想要的 User Model ,比如说不想要信箱验证功能的话,就不要引入 MustVerifyEmail 属性。
/vendor/laravel/framework/src/Illuminate/Foundation/Auth/User.php
<?php
namespace Illuminate\Foundation\Auth;
use Illuminate\Auth\Authenticatable;
use Illuminate\Auth\MustVerifyEmail;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Auth\Access\Authorizable;
class User extends Model implements
AuthenticatableContract,
AuthorizableContract,
CanResetPasswordContract
{
use Authenticatable, Authorizable, CanResetPassword, MustVerifyEmail;
}
guards 用於定义不同的"关口",各个关口会察看不同的身分证,或是用不同的方法来检查身分证。
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
],
像这边定义了 web 这个关口,只检查 providers 中的 users 身分证,并且用 session 的方式进行检查。
检查的方式有许多种,除了 session 外 Laravel 预设的套件中有 passport 跟 sanctum ,或是第三方套件的 jwt。
可以定义多个关口
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'admin' => [
'driver' => 'session',
'provider' => 'admins',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
],
],
当要进行身分检查时,可以先指定要用哪个 guard 进行检查,如果没有指定就是使用 config/auth.php 设定的 default 值。
// 在 Admin 的资料中找的到的话才能验证成功
Auth::guard('admin')->login($user);
Auth::guard('admin')->attempt($crednetials);
我们可以在路由中加上 auth 这个中介层,检查使用者的身分,如果身分符合的话才放行。
/routes/auth.php
Route::post('/logout', [AuthenticatedSessionController::class, 'destroy'])
->middleware('auth')
->name('logout');
auth 只是个快捷键,在 app/Http/Kernel.php 中定义了 auth 对应的中介层类别。
app/Http/Kernel.php
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
//...
];
再仔细看看这个 Authenticate 类别,也只是继承了框架底层的类别,详细进行身分验证的检查都在 Illuminate\Auth\Middleware\Authenticate 中。
在专案的 app 目录底下的 Authenticate 目前只用来指定当身分检查失败时要导向哪个页面。
/app/Http/Middleware/Authenticate.php
<?php
namespace App\Http\Middleware;
use Illuminate\Auth\Middleware\Authenticate as Middleware;
class Authenticate extends Middleware
{
protected function redirectTo($request)
{
if (! $request->expectsJson()) {
return route('login'); // 身分验证失败就导向登入页面
}
}
}
当加入 auth 中介层时如果没有额外指定,就是用预设的 guard 进行检查。
要指定不同的 guard 话,加上 : 後指定
Route::get('/flights', function () {
// 通过 admin 检查的用户才能进入路由
})->middleware('auth:admin');
Laravel 预设的身分检查是用基础的 session-cookie 方式,如果想要改成其他方法的话可以利用套件。
这边简单介绍几个可以用的套件,各自的安装跟使用又都是大长篇就先不细说。
Laravel 预设包含的套件之一,可以用来进行 Outh2 验证。
Laravel 预设包含的套件之一,以简易的 token 进行验证,可以应用於 SPA 跟行动装置的 API 验证。
顾名思义登入後就产出 jwt ,让客户端存好後使用。
帮 Model 产出 API key 并用来验证,可以用於 S2S 的 API 验证。
<<: Day 24: Lab-Distributed Machine Learning with Google Cloud ML
>>: [Day 24] 阿嬷都看得懂的响应式网页设计在干嘛
大家好,我是长风青云。我真的没想到今天我会讲这麽久的影片QAQ 然後我可爱的(?)学弟居然在最後密我...
今日文章目录 > - 三角型使用情境 > - 用CSS画三角型 > - 参考资料...
荀子劝学篇中有一段是这样的: 「积土成山,风雨兴焉;积水成渊,蛟龙生焉;.....。故不积蹞步,无以...
今天要认识的Design Pattern我觉得比较难,但我会尽量以简单的方法让大家了解 Visi...
上一篇提到可以从 Search Console 看到 6 种不同的流量来源,而 SC 提供的概要是用...