laragear / email-login
通过电子邮件1分钟内验证用户。
Requires
- php: ^8.1
- illuminate/auth: 10.*|11.*
- illuminate/config: 10.*|11.*
- illuminate/http: 10.*|11.*
- illuminate/mail: 10.*|11.*
- illuminate/support: 10.*|11.*
- laragear/token-action: ^1.2.1
Requires (Dev)
- laragear/meta-testing: 2.*
- orchestra/testbench: 8.*|9.*
Suggests
- illuminate/queue: For queueing emails. (10.*|11.*)
README
通过电子邮件1分钟内验证用户。
<form method="post" action="/auth/email/send"> @csrf <input type="email" name="email" placeholder="me@email.com"> <button type="submit">Log in</button> </form>
保持此包免费
您的支持使我能够保持此包免费、更新和可维护。或者,您可以通过 传播信息!
安装
然后调用Composer来检索包。
composer require laragear/email-login
1分钟快速开始
在安装后,Email Login非常简单:将您想验证的用户电子邮件放入表单中,然后就会发送一封包含单次链接的电子邮件给他以进行验证。
首先,使用email-login:install
Artisan命令安装配置文件和基础控制器。
php artisan email-login:install
之后,确保您已使用包含在Laragear\EmailLogin\Http\Routes
类的路由注册器帮助程序注册了登录电子邮件将用于验证的路由。
use Illuminate\Routing\Route; use Laragear\EmailLogin\Http\Routes as EmailLoginRoutes; Route::view('welcome'); // Register the default Mail Login routes EmailLoginRoutes::register();
提示
除了控制器外,您还可以通过参数更改电子邮件登录的路由路径。
use Laragear\EmailLogin\Http\Routes as EmailLoginRoutes; EmailLoginRoutes::register( send: '/send-email-here', login: '/login-from-email-here', controller: 'App/Http/Controllers/MyEmailLoginController', );
最后,通过在应用程序的任何位置进行POST
到auth/email
,添加一个“登录”框来接收用户电子邮件。
<form method="post" action="/auth/email/send"> @csrf <input type="email" name="email" placeholder="me@email.com"> <button type="submit">Log in</button> </form>
就这样,您的用户就可以用电子邮件登录了。
此包会为您处理整个逻辑,但您始终可以使用自己的路由和控制器完全手动操作。
发送登录电子邮件
要手动实现登录电子邮件,您需要从表单提交中捕获用户凭据。EmailLoginRequest
为您做了大部分工作。
如果您使用的是Laravel默认设置,请求将自动验证电子邮件。您只需要返回sendAndBack()
方法以将用户重定向回表单。
use Illuminate\Support\Facades\Route; use Laragear\EmailLogin\Http\Requests\EmailLoginRequest; Route::post('/auth/email/send', function (EmailLoginRequest $email) { return $email->sendAndBack(); });
如果您需要在发送电子邮件之前执行某些操作,可以单独使用send()
和back()
,如果要扩展电子邮件验证规则,则可以使用validate()
方法。
use Illuminate\Support\Facades\Route; use Laragear\EmailLogin\Http\Requests\EmailLoginRequest; Route::post('/auth/email/send', function (EmailLoginRequest $email) { $email->validate([ 'email' => 'required|email:rfc,dns' ]); $email->send(); session()->flash('message', 'Email sent successfully!'); return back(); });
sendAndBack()
和send()
都返回true
,如果找到具有凭据的用户并发送了电子邮件(或已排队待发送),则返回false
,如果用户不存在。某些应用程序可以通过隐藏用户存在性而没问题,但某些应用程序可能希望显示用户不存在。
if ($email->send()) { session()->flash('message', 'Email sent successfully!'); } else { throw ValidationException::withMessages([ 'email' => 'The user with the email does not exist' ]); }
自定义凭据
在发送电子邮件登录时,验证的数据用于通过守卫的用户提供者查找要验证的用户。例如,如果您验证了username
键,则只使用该键来查找用户并发送电子邮件。
use Illuminate\Support\Facades\Route; use Laragear\EmailLogin\Http\Requests\EmailLoginRequest; Route::post('/auth/email/send', function (EmailLoginRequest $email) { $email->validate([ 'username' => 'required|string|exists:users' ]); return $email->sendAndBack(); });
您可以使用带有请求输入中用作凭据的键的列表的withCredentials()
方法来覆盖凭据以查找用户。该列表可能不同于验证的请求输入。
use Illuminate\Support\Facades\Route; use Laragear\EmailLogin\Http\Requests\EmailLoginRequest; Route::post('/auth/email/send', function (EmailLoginRequest $email) { $email->validate([ // ... ]); return $email->withCredentials(['username', 'mail'])->sendAndBack(); });
键也可以是接收查询以查找用户的回调。
$email->withCredentials([ 'mail', fn($query) => $query->where('is_human', '>', 0.5) ]);
或者,如果您提供键值对,则键的值将用作凭据值。
use Illuminate\Support\Facades\Route; use Laragear\EmailLogin\Http\Requests\EmailLoginRequest; Route::post('/auth/email/send', function (EmailLoginRequest $email) { $email->validate([ 'email' => 'required|email' ]); return $email->withCredentials([ 'mail' => $email->email, 'banned_at' => null, fn($query) => $query->where('standing', '>', 0.5) ])->sendAndBack(); });
登录过期
通过电子邮件发送的登录链接有一个过期时间,默认为5分钟。您可以通过配置或使用withExpiration()
方法在运行时更改它,方法包括传递分钟数、DateTimeInterface
实例或传递给strtotime()
的字符串。
use Illuminate\Support\Facades\Route; use Laragear\EmailLogin\Http\Requests\EmailLoginRequest; Route::post('/auth/email/send', function (EmailLoginRequest $email) { return $email->withExpiration(10)->sendAndBack(); });
自定义记住键
如果您的请求包含remember
键,并且它是true的,则在用户登录时,用户将被记住。如果键不同,您可以通过withRemember()
方法设置带有键名的字符串。
use Illuminate\Support\Facades\Route; use Laragear\EmailLogin\Http\Requests\EmailLoginRequest; Route::post('/auth/email/send', function (EmailLoginRequest $email) { return $email->withRemember('remember_me')->sendAndBack(); });
或者,可以发出任何其他内容作为条件,例如布尔值或回调。
use Illuminate\Support\Facades\Route; use Laragear\EmailLogin\Http\Requests\EmailLoginRequest; Route::post('/auth/email/send', function (EmailLoginRequest $email) { return $email->withRemember($email->boolean('remember_me'))->sendAndBack(); });
指定守卫
默认情况下,电子邮件登录假设用户将使用默认守卫进行身份验证,在大多数vanilla Laravel应用程序中是web
。您可能想要在配置中更改默认守卫,或使用withGuard()
在运行时更改它。
use Illuminate\Support\Facades\Route; use Laragear\EmailLogin\Http\Requests\EmailLoginRequest; Route::post('/auth/email/send', function (EmailLoginRequest $email) { return $email->withGuard('admin')->sendAndBack(); });
电子邮件URL链接
您可以通过配置更改电子邮件登录将指向的URL,或使用withPath()
、withAction()
和withRoute()
方法在运行时更改。如果需要,您还可以使用数组作为第二个参数设置参数。
use Illuminate\Support\Facades\Route; use Laragear\EmailLogin\Http\Requests\EmailLoginRequest; Route::post('/auth/email/send', function (EmailLoginRequest $email) { return $email->withRoute('auth.email.login', ['is_cool' => true])->sendAndBack(); });
您还可以使用withParameters()
方法仅向配置中设置的默认URL追加查询参数。
use Illuminate\Support\Facades\Route; use Laragear\EmailLogin\Http\Requests\EmailLoginRequest; Route::post('/auth/email/send', function (EmailLoginRequest $email) { return $email->withParameters(['is_cool' => true])->sendAndBack(); });
警告
必须存在该路由。此路由应显示一个登录表单,而不是立即登录用户。请参阅从邮件登录。
自定义Mailable
使用自己的Mailable类的基本方法是通过withMailable()
方法设置它,可以是类名(由容器实例化)或Mailable实例。
use App\Mails\MyLoginMailable; use Illuminate\Support\Facades\Route; use Laragear\EmailLogin\Http\Requests\EmailLoginRequest; Route::post('/auth/email/send', function (EmailLoginRequest $email) { return $email->withMailable(MyLoginMailable::class)->sendAndBack(); });
或者,您可能想使用回调来自定义包含的Mailable实例。该回调接收LoginEmail
mailable。在回调内部,您可以自由修改mailable,例如更改视图或目的地,甚至返回一个新的Mailable。
use Illuminate\Support\Facades\Route; use Laragear\EmailLogin\Http\Requests\EmailLoginRequest; use Laragear\EmailLogin\Mails\LoginEmail; Route::post('/auth/email/send', function (EmailLoginRequest $email) { return $email->withMailable(function (LoginEmail $mailable) { $mailable->view('my-login-email', ['theme' => 'blue']); $mailable->subject('Login to this awesome app'); })->sendAndBack(); });
不透明节流
如果您想不透明地节流发送电子邮件,只需使用withThrottle()
方法并指定秒数。在这段时间内,电子邮件将不会发送。这可以避免大量电子邮件。
use Illuminate\Support\Facades\Route; use Laragear\EmailLogin\Http\Requests\EmailLoginRequest; Route::post('/auth/email/send', function (EmailLoginRequest $email) { return $email->withThrottle(30)->sendAndReturnBack(); });
节流使用与存储电子邮件登录意图相同的缓存和请求指纹(IP),默认情况下。您可以将缓存存储更改为使用第二个名称,甚至可以将键作为第三个参数用于节流器。
use Illuminate\Support\Facades\Route; use Laragear\EmailLogin\Http\Requests\EmailLoginRequest; Route::post('/auth/email/send', function (EmailLoginRequest $email) { $key = strtolower($email->input('email')); return $email->withThrottle(30, 'redis', $key)->sendAndReturnBack(); });
添加元数据
您可以使用withMetadata()
方法保存仅对登录尝试有效的数据。您可以在其中设置键和值的数组,您可以在登录成功时稍后检索。
use Illuminate\Support\Facades\Route; use Laragear\EmailLogin\Http\Requests\EmailLoginRequest; use Laragear\EmailLogin\Http\Requests\LoginByEmailRequest; // Send the email and save the metadata internally. Route::post('/auth/email/send', function (EmailLoginRequest $request) { return $request ->withMetadata(['is_cool' => true]) ->sendAndReturnBack(); }); // Show the login form with the metadata. Route::get('/auth/email/login', function (LoginByEmailRequest $request) { return view('laragear::email-login.web.login', [ 'is_cool' => $request->metadata('is_cool') ]); });
提示
元数据不会在电子邮件链接中传输,而是作为电子邮件登录意图的一部分存储在您的应用程序缓存中。
从邮件登录
从电子邮件的登录过程必须在两个控制器操作中完成:一个显示表单,另一个验证用户。这两个路由都应该使用guest
中间件,以避免被已验证的用户触发。
警告
登录必须在两个控制器动作中完成,因为 一些电子邮件客户端和服务器会预加载、缓存和/或预取登录链接。虽然这通常是为了加速导航或过滤恶意网站,但这会意外地让用户在非其设备上登录,并导致后续的登录尝试失败。
为了避免这种意外的身份验证,创建一个显示登录表单的路由,以及另一个用于验证用户的路由。
使用 LoginByEmailRequest
返回包含登录表单的视图,并在两个用户上登录用户。
- 当登录无效或过期时,会向用户显示 HTTP 419(过期)错误,而不是视图。否则,您可以使用包含的
laragear::email-login.web.login
视图来显示表单。 - 当收到登录表单提交时,用户将被自动登录。
use Illuminate\Http\Request; use Illuminate\Support\Facades\Route; use Laragear\EmailLogin\Http\Requests\LoginByEmailRequest; Route::middleware('guest')->group(function () { // Show the form to log in. Route::get('/auth/login/mail', function (LoginByEmailRequest $request) { return view('laragear::email-login.web.login') })->name('login.mail'); // User logged in automatically, show him the dashboard. Route::post('/auth/login/mail', function (LoginByEmailRequest $request) { return $request->toIntended() }); })
检索元数据
如果您在发送电子邮件之前 设置了元数据,则可以使用 metadata()
方法以及 dot.notation
中的键来检索它,并可选地提供一个默认值,如果未设置。
use Laragear\EmailLogin\Http\Requests\LoginByEmailRequest; use Illuminate\Support\Facades\Route; Route::get('auth/login/mail', function (LoginByEmailRequest $request) { return view('laragear::email-login.web.login', [ 'is_cool' => $request->metadata('is_cool'); ]); });
电子邮件登录代理
如果您想要一种更 手动 的方式来登录用户,请使用 EmailLoginBroker
,这是表单请求助手在幕后使用的。
要创建电子邮件登录意向,请使用 create()
。它需要身份验证守卫、用户 ID 和过期时间。它返回一个随机令牌,该令牌应通过电子邮件传输。
use App\Models\User; use Illuminate\Http\Request; use Illuminate\Support\Facades\Mail;use Illuminate\Support\Facades\Route; use Laragear\EmailLogin\EmailLoginBroker;use Laragear\EmailLogin\Mails\LoginEmail; Route::post('/send-login-email', function (Request $request, EmailLoginBroker $broker) { $request->validate([ 'email' => 'required|email' ]); // Find the user by the email $user = User::where('email', $request->email)->first(); // Send the email if the user exists. if ($user) { $url = url('/login-by-email', [ 'token' => $broker->create('web', $user->id), 'guard' => 'web', ]); // Send the email with the url to the user. LoginEmail::make($user, $url)->to($request->email)->send(); } session()->flash('message', 'Login email sent successfully!'); return back(); });
当用户被重定向到您的电子邮件登录表单后,请使用带有令牌的 get()
方法检索 EmailLoginIntent
。
use App\Models\User; use Illuminate\Http\Request; use Illuminate\Support\Facades\Mail;use Illuminate\Support\Facades\Route; use Laragear\EmailLogin\EmailLoginBroker;use Laragear\EmailLogin\Mails\LoginEmail; Route::get('/login-by-email', function (Request $request, EmailLoginBroker $broker) { // If the intent exists, show him the login form. if ($broker->get($request->query('token'))) { return view('my-email-login-view'); } // If it doesn't exist, redirect the user back to the initial login. return redirect('send-login-email'); });
一旦收到表单提交,请使用 pull()
方法从缓存存储中删除意向,并使用 EmailLoginIntent
实例数据登录用户。
use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Auth; use Illuminate\Http\Request; use Laragear\EmailLogin\EmailLoginBroker; Route::post('/login-by-email', function (Request $request, EmailLoginBroker $broker) { $intent = $broker->pull($request->query('token')); // If the intent doesn't exist, bail out. if (!$intent) { return redirect('send-login-email'); } // Log in the user using the intent data. Auth::guard($intent->guard)->loginUsingId($intent->id, $intent->remember); // Regenerate the session for security. $request->session()->regenerate(); return redirect('/dashboard'); });
自定义令牌字符串
在生成电子邮件登录令牌时,将生成一个随机的 ULID。您可以通过设置一个回调来更改默认的生成器,该回调接收 EmailLoginIntent
并返回一个(希望非常)随机的字符串。您可以在 AppServiceProvider::register()
中这样做。
use Illuminate\Support\Str; use Laragear\EmailLogin\EmailLoginBroker; use Laragear\EmailLogin\EmailLoginIntent; public function register() { EmailLoginBroker::$tokenGenerator = function (EmailLoginIntent $intent) { return Str::random(128); }; }
高级配置
邮件登录旨在开箱即用,但您可以通过发布配置文件来覆盖配置,如果您不是使用 Laravel 的默认设置。
php artisan vendor:publish --provider="Laragear\EmailLogin\EmailLoginServiceProvider" --tag="config"
之后,您将收到一个类似于下面的 config/email-login.php
配置文件
return [ 'guard' => null, 'route' => [ 'name' => 'login.mail', 'view' => 'laragear::email-login.web.login', ], 'throttle' => [ 'store' => null, 'prefix' => 'throttle' ], 'expiration' => 5, 'cache' => [ 'store' => null, 'prefix' => 'email-login' ], 'mail' => [ 'mailer' => null, 'connection' => null, 'queue' => null, 'view' => 'laragear::email-login.mail.login', ], ];
守卫
return [ 'guard' => null, ];
要使用的默认身份验证守卫。当为 null
时,将回退到应用程序默认值,通常是 web
。为守卫设置的 User Provider 用于查找用户。
路由名称 & 视图
return [ 'route' => [ 'name' => 'login.mail', 'view' => 'laragear::email-login.web.login', ], ];
此命名路由在电子邮件中链接,其中包含用于登录用户的视图表单。
节流
return [ 'throttle' => [ 'store' => null, 'prefix' => 'throttle' ], ];
当 节流电子邮件 时,将使用此配置来设置要使用的缓存存储和前缀。
缓存
return [ 'cache' => [ 'store' => null, 'prefix' => 'email-login' ], ];
电子邮件登录意向被保存到给定持续时间的缓存中。您在这里可以更改用于存储它们的缓存存储和前缀。当为 null
时,它将使用默认的应用程序存储。
链接过期
return [ 'expiration' => 5, ];
当发送链接时,将生成一个带有过期时间的已签名 URL。您可以控制链接在被缓存存储清除之前保持有效的时间(以分钟为单位)。
邮件驱动程序
return [ 'mail' => [ 'mailer' => null, 'connection' => null, 'queue' => null, 'markdown' => 'laragear::email-login.mail.login', ], ];
这指定了用于发送登录电子邮件的邮件驱动程序,以及接收它的队列连接和名称。当为 null
时,将回退到应用程序默认值,通常是 smtp
。
这还设置了用于创建电子邮件的默认视图,它 使用 Markdown。
Laravel Octane 兼容性
- 没有单例使用过时的应用程序实例。
- 没有单例使用过时的配置实例。
- 没有单例使用过时的请求实例。
- 可写入的两个静态属性是
LoginByMailRequest::$destroyOnRegeneration
EmailLoginBroker::$tokenGenerator
使用此包与 Laravel Octane 一起使用不应有任何问题。
安全
如果您发现任何与安全相关的问题,请通过电子邮件 darkghosthunter@gmail.com 联系,而不是使用问题跟踪器。
发送电子邮件后的身份验证阻止。
一旦将登录电子邮件发送给用户,由于它不会检查除有效电子邮件登录意图之外的内容,所以 LoginByEmailRequest
将无法阻止身份验证过程。
例如,如果用户在发送登录电子邮件后被禁止,用户仍然可以进行身份验证。
为了避免这种情况,扩展 LoginByEmailRequest
并修改 login()
方法以在手动检索的用户上添加进一步的检查。然后,在您选择的登录控制器中使用此新类。
use App\Models\User; use Illuminate\Contracts\Auth\Authenticatable; use Illuminate\Contracts\Auth\StatefulGuard; use Illuminate\Validation\ValidationException; use Laragear\EmailLogin\Http\Requests\LoginByEmailRequest; class MyLoginRequest extends LoginByEmailRequest { /** * Proceed to log in the user after a successful form submission. */ protected function login(StatefulGuard $guard, mixed $id, bool $remember): void { $user = User::whereNull('banned_at')->find($id); if (!$user) { throw ValidationException::withMessages([ 'email' => 'The user for this email has been banned.' ]); } $guard->login($user, $remember); } }
许可证
MIT 许可证 (MIT)。有关更多信息,请参阅 许可证文件。
Laravel 是 Taylor Otwell 的商标。版权所有 © 2011-2024 Laravel LLC。