如何在不要求用户登录Laravel的情况下验证电子邮件

如何在不要求用户登录Laravel的情况下验证电子邮件,laravel,laravel-authentication,laravel-controller,Laravel,Laravel Authentication,Laravel Controller,我正在开发一个Laravel应用程序。我的应用程序正在使用Laravel内置的身份验证功能。在Laravel auth中,当用户注册时,将发送验证电子邮件。当用户验证电子邮件时,单击电子邮件内的链接,如果用户尚未登录,则用户必须再次登录以确认电子邮件 验证控制器 类验证控制器扩展控制器 { 使用验证邮件、重定向SUSERSBASEDON角色; /** *创建一个新的控制器实例。 *@返回无效 */ 公共函数构造() { $this->middleware('auth'); $this->midd

我正在开发一个Laravel应用程序。我的应用程序正在使用Laravel内置的身份验证功能。在Laravel auth中,当用户注册时,将发送验证电子邮件。当用户验证电子邮件时,单击电子邮件内的链接,如果用户尚未登录,则用户必须再次登录以确认电子邮件

验证控制器

类验证控制器扩展控制器
{
使用验证邮件、重定向SUSERSBASEDON角色;
/**
*创建一个新的控制器实例。
*@返回无效
*/
公共函数构造()
{
$this->middleware('auth');
$this->middleware('signed')->only('verify');
$this->middleware('throttle:6,1')->only('verify','resend');
}
公共函数重定向路径()
{
返回$this->getRedirectTo(Auth::guard()->user());
}
}
我试着对这句话发表评论

$this->middleware('auth');

但它不起作用,反而抛出了一个错误。即使用户未登录,如何使Laravel能够验证电子邮件?

首先,删除行
$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);
}
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);
}
这将覆盖
验证用户
特征中的方法,并删除授权检查

安全性(如果我错了,请纠正我!)


它仍然是安全的,因为请求是经过签名和验证的。如果某人以某种方式获得了对验证电子邮件的访问权限,则可以验证其他用户的电子邮件地址,但在99%的情况下,这几乎不存在任何风险。

如果您想在不登录的情况下激活用户帐户,您可以分两步完成此操作

1-删除或注释VerificationController中的身份验证中间件

示例如下:

public function __construct()
{
    //$this->middleware('auth');
    $this->middleware('signed')->only('verify');
    $this->middleware('throttle:6,1')->only('verify', 'resend');
}
2-由于verify route通过{id},您只需编辑verify函数即可通过route id请求找到用户,如下代码所示:

文件路径:::\yourproject\vendor\laravel\framework\src\illumb\Foundation\Auth\VerifiesEmails.php

$user = User::findOrfail($request->route('id'));
完整示例

public function verify(Request $request)
{
    $user = User::findOrfail($request->route('id'));

    if (! hash_equals((string) $request->route('id'), (string) $user->getKey())) {
        throw new AuthorizationException;
    }

    if (! hash_equals((string) $request->route('hash'), sha1($user->getEmailForVerification()))) {
        throw new AuthorizationException;
    }

    if ($user->hasVerifiedEmail()) {
        return redirect($this->redirectPath())->with('verified', true);
    }

    if ($user->markEmailAsVerified()) {
        event(new Verified($request->user()));
    }

    return redirect($this->redirectPath())->with('registered', true);
}

这里有一个更适合未来的解决方案:

类验证控制器扩展控制器
{
// …
使用电子邮件{
验证为原始验证;
}
/**
*创建一个新的控制器实例。
*
*@返回无效
*/
公共函数构造()
{
$this->middleware('auth');//不要删除此
$this->middleware('signed')->only('verify');
$this->middleware('throttle:6,1')->only('verify','resend');
}
/**
*将已验证用户的电子邮件地址标记为已验证。
*
*@param Request$Request
*@返回响应
*
*@Towns AuthorizationException
*/
公共功能验证(请求$Request)
{
$request->setUserResolver(函数()使用($request){
返回用户::findOrFail($request->route('id'));
});
返回$this->originalVerify($request);
}
}
因此,当未经验证的用户单击电子邮件确认链接时,将发生以下情况:

  • 用户将被重定向到登录视图1
  • 用户输入凭证;成功登录2
  • 用户将被重定向回电子邮件确认URL
  • 电子邮件将被标记为已确认

  • 1此时,电子邮件将不会标记为已确认


    2用户可能多次输入错误凭据。一旦他输入了正确的凭据,他将被重定向到预期的电子邮件确认URL。

    您不应该删除
    $this->middleware('auth')
    ,因为这会影响重定向。如果删除它,未经身份验证的用户将重定向到“/email/verify”,而不是“/login”

    所以
    $this->中间件('auth')将更改为
    $this->middleware('auth')->除了('verify')

    同时将“验证邮件”中的“验证”功能复制到“验证控制器”中

    在函数顶部添加这两行代码

    $user = User::find($request->route('id'));
    
    auth()->login($user);
    

    因此,您以编程方式登录用户,然后执行进一步的操作,以允许对未登录(即未经验证)的用户进行电子邮件验证:

    更改为:app/Http/Controllers/Auth/VerificationController.php:

  • $this->中间件('auth')
    $this->中间件('auth')->除了('verify')
  • VerifiesEmails
    trait复制
    verify()
    方法
  • 编辑验证方法,使其在没有预期的
    $request->user()
    数据的情况下工作
  • VerificationController
    中我的
    Verification()
    方法如下所示:

    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);
    }
    
    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的完整性。签名检查URL创建后是否已更改。尝试更改url中的id、过期时间或签名,会导致错误-非常有效和有用的中间件来保护verify()方法

    有关更多信息:

    (可选)

    我将用户重定向到登录路径,而不是预定路径,原因有二。1) 登录后,它会尝试将用户重定向到电子邮件验证链接,导致错误;2) 我想使用附加到重定向的已验证的true flash数据,如果用户已成功验证其电子邮件地址,则在登录页面上显示警报

    我的登录页面警报示例:

    @if(session()->has('verified'))
        <div class="alert alert-success">Your email address has been successfully verified.</div>
    @endif
    
    @if(session()->has('verified'))
    您的电子邮件地址已成功验证。
    @恩迪夫
    
    建议

    如果您对我如何改进此代码有任何建议,请联系我们