我正在开发Laravel应用程序。我的应用程序使用Laravel内置的身份验证功能。当用户注册时,在Laravel身份验证中,将发送验证电子邮件。当用户验证电子邮件时,请单击电子邮件中的链接,如果用户尚未登录,则必须再次登录以确认电子邮件。
VerificationController
class VerificationController extends Controller
{
use VerifiesEmails, RedirectsUsersBasedOnRoles;
/**
* Create a new controller instance.
* @return void
*/
public function __construct()
{
$this->middleware('auth');
$this->middleware('signed')->only('verify');
$this->middleware('throttle:6,1')->only('verify', 'resend');
}
public function redirectPath()
{
return $this->getRedirectTo(Auth::guard()->user());
}
}
我尝试对此行发表评论。
$this->middleware('auth');
但是它不起作用,而是抛出一个错误。即使用户未登录,如何使Laravel能够验证电子邮件?
答案 0 :(得分:4)
// For Laravel 6 and Above
use Illuminate\Auth\Events\Verified;
use Illuminate\Http\Request;
use App\User;
// comment auth middleware
//$this->middleware('auth');
public function verify(Request $request)
{
$user = User::find($request->route('id'));
if (!hash_equals((string) $request->route('hash'), sha1($user->getEmailForVerification()))) {
throw new AuthorizationException;
}
if ($user->markEmailAsVerified())
event(new Verified($user));
return redirect($this->redirectPath())->with('verified', true);
}
答案 1 :(得分:2)
首先,像以前一样删除$this->middleware('auth');
行。
接下来,将verify
特性中的VerifiesEmails
方法复制到您的VerificationController
中,并进行一些修改。该方法应如下所示:
public function verify(Request $request)
{
$user = User::find($request->route('id'));
if ($user->markEmailAsVerified())
event(new Verified($user));
return redirect($this->redirectPath())->with('verified', true);
}
这将覆盖VerifiesUsers
特征中的方法,并删除授权检查。
安全性(如果我输入错了,请纠正我!)
由于请求已签名并验证,因此它仍然是安全的。如果某人可以某种方式访问验证电子邮件,则可以验证另一个用户的电子邮件地址,但是在99%的情况下,这根本没有风险。
答案 2 :(得分:1)
这是该问题的更未来解决方案:
class VerificationController extends Controller
{
// …
use VerifiesEmails {
verify as originalVerify;
}
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth'); // DON'T REMOVE THIS
$this->middleware('signed')->only('verify');
$this->middleware('throttle:6,1')->only('verify', 'resend');
}
/**
* Mark the authenticated user's email address as verified.
*
* @param Request $request
* @return Response
*
* @throws AuthorizationException
*/
public function verify(Request $request)
{
$request->setUserResolver(function () use ($request) {
return User::findOrFail($request->route('id'));
});
return $this->originalVerify($request);
}
}
因此,当未经身份验证的用户单击电子邮件确认链接时,将发生以下情况:
1 此时,该电子邮件将不会被标记为已确认。
2 用户可能多次输入错误的凭据。输入正确的凭据后,他将被重定向到预期的电子邮件确认URL。
答案 3 :(得分:1)
这是我对这种情况的看法。验证需要用户登录才能完成验证,因此我们可以使用我们在链接中收到的 ID 覆盖验证功能和登录用户。这是安全的,因为如果 Laravel 无法验证来自 URL 的签名,则不会调用验证函数,因此即使有人修改 URL,他们也无法绕过它。
转到您的 VerificationController 并在文件末尾添加以下函数。
public function verify(Request $request)
{
if (!auth()->check()) {
auth()->loginUsingId($request->route('id'));
}
if ($request->route('id') != $request->user()->getKey()) {
throw new AuthorizationException;
}
if ($request->user()->hasVerifiedEmail()) {
return redirect($this->redirectPath());
}
if ($request->user()->markEmailAsVerified()) {
event(new Verified($request->user()));
}
return redirect($this->redirectPath())->with('verified', true);
}
注意
确保您将 'config/session.php' 中的 same_site 值设置为 'lax'。如果它设置为“严格”,那么如果您是从另一个站点重定向的,它将不会保留会话。例如,如果您点击来自 Gmail 的验证链接,那么您的会话 cookie 将不会保留,因此它不会将您重定向到仪表板,但它会在数据库中设置“email_verified_at”字段,标记验证成功。用户不会知道发生了什么,因为它会将用户重定向到登录页面。当您将其设置为“严格”时,如果您直接在浏览器地址栏中复制验证链接,它将起作用,但如果用户从 Gmail 网络客户端单击该链接,则不起作用,因为它使用重定向来跟踪链接。
答案 4 :(得分:0)
因为redirect
要回家
并且由于需要home view
auth
,因此它要求您登录以进行验证
如果您不想要
您需要更改
的
redirect to
到另一个不需要登录的页面,例如
主页
,写在其中的页面您已通过验证,依此类推
任何页面都不需要auth
:D
为此
您只需更改
protected $redirectTo = '/home';
像这样
protected $redirectTo = '/';
这是在VerificationController中 如果没有,只需添加:D
答案 5 :(得分:0)
您不应完全删除$this->middleware('auth')
,因为这会影响重定向。如果删除它,未经身份验证的用户将被重定向到“ / email / verify”,而不是“ / login”
因此$this->middleware('auth');
将在“ VerificationController”中更改为$this->middleware('auth')->except('verify');
还将“验证”功能从“ VerifyEmails”复制到“ VerificationController”
在函数顶部添加这两行代码
$user = User::find($request->route('id'));
auth()->login($user);
因此您将以编程方式登录用户,然后执行进一步的操作
答案 6 :(得分:0)
允许未登录(即未经身份验证)用户进行电子邮件验证的解决方案:
更改为:app/Http/Controllers/Auth/VerificationController.php:
$this->middleware('auth');
到 $this->middleware('auth')->except('verify');
verify()
trait 复制 VerifiesEmails
方法。$request->user()
数据的情况下工作。我在 verify()
中的 VerificationController
方法如下所示:
public function verify(\Illuminate\Http\Request $request)
{
$user = User::find($request->route('id'));
if ($request->route('id') != $user->getKey()) {
throw new AuthorizationException;
}
if ($user->markEmailAsVerified())
event(new Verified($user));
return redirect()->route('login')->with('verified', true);
}
签名中间件
Laravel 使用名为 signed
的中间件来检查应用程序生成的 URL 的完整性。 Signed 检查 URL 自创建以来是否已更改。尝试更改 id、到期时间或 url 中的签名会导致错误 - 非常有效和有用的中间件来保护 verify() 方法
更多信息:https://laravel.com/docs/8.x/urls#signed-urls
(可选)
出于两个原因,我将我的用户重定向到登录路由,而不是预期的路由。 1) 登录后,尝试将用户重定向到邮箱验证链接,导致错误; 2) 我想使用附加到重定向的经过验证的真实 Flash 数据,如果用户已成功验证其电子邮件地址,则在登录页面上显示警报。
我的登录页面警报示例:
@if(session()->has('verified'))
<div class="alert alert-success">Your email address has been successfully verified.</div>
@endif
建议
如果您对我如何改进此代码有任何建议,请告诉我。我很乐意编辑这个答案。
答案 7 :(得分:-1)
如果不使用Laravel内置的电子邮件验证逻辑,我可能会解决这个问题。
相反,我将按照以下步骤进行操作。
只是一个建议。