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

时间:2018-12-21 13:15:03

标签: laravel laravel-authentication laravel-controller

我正在开发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能够验证电子邮件?

8 个答案:

答案 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. 用户将被重定向到登录视图 1
  2. 用户输入凭据;成功登录 2
  3. 用户将被重定向回电子邮件确认URL
  4. 电子邮件将被标记为已确认

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:

  1. $this->middleware('auth');$this->middleware('auth')->except('verify');
  2. verify() trait 复制 VerifiesEmails 方法。
  3. 编辑验证方法以在没有预期的 $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内置的电子邮件验证逻辑,我可能会解决这个问题。

相反,我将按照以下步骤进行操作。

  • 创建一个带有令牌字段和电子邮件的验证表。
  • 用户注册后,在表中使用唯一令牌及其电子邮件生成新行。
  • 向他们发送一封电子邮件,其中包含指向网站的链接,并将令牌作为查询参数
  • 用户访问网站时,通过令牌查找验证并获取电子邮件
  • 通过电子邮件获取用户并标记为已验证(可能是用户表上的某些字段)。
  • 删除验证
  • 通过会话消息将其重定向到您想要的任何地方,表明它们已通过验证。

只是一个建议。