1

我正在使用带有内置用户电子邮件验证流程的 Laravel 7.3。

我正在尝试在流程中实现“返回 URL”,以便在验证用户的电子邮件后将用户重定向到特定的 URL。这对于用户在应用程序上启动操作(例如订阅)很有用。该操作需要一个帐户,并且一个帐户需要验证。

我在流程的每一步都在 URL 中包含了返回 URL,并且正在生成一个如下所示的验证 URL:

https://localhost/email/verify/287/23e499466a6bad538df7ce48e090294502502a86?expires=1630005974&signature=f77d57494132c71735e744a224e5116974fec33b482ec5874c40ca6321d200e6&return=https://localhost/subscribe

到目前为止,一切都很好。但是,这会返回 403。跟踪它会导致我:

vendor\laravel\framework\src\Illuminate\Routing\UrlGenerator.php/ Illuminate\Routing\UrlGenerator

public function hasCorrectSignature(Request $request, $absolute = true)
{
    $url = $absolute ? $request->url() : '/'.$request->path();

    $original = rtrim($url.'?'.Arr::query(
        Arr::except($request->query(), 'signature')
    ), '?');
            
    $signature = hash_hmac('sha256', $original, call_user_func($this->keyResolver));
    
    return hash_equals($signature, (string) $request->query('signature', ''));
}

倾倒$original向我展示了这一点:https://localhost/email/verify/287/23e499466a6bad538df7ce48e090294502502a86?expires=1630005974&return=https%3A%2F%2Flocalhost%2Fsubscribe%2F2

这是我所期待的,但函数返回false,它会抛出 403。

我无法想象这是一个不寻常的用例,但我正在努力在网上找到有关实现它的最佳方法的任何信息。

下面是我构建 URL 的方式,这在我的VerifyEmail通知中。我尝试添加return作为签名路由本身的参数,但它也是 403s:

$url = URL::temporarySignedRoute(
    'verification.verify',
    Carbon::now()->addMinutes(Config::get('auth.verification.expire', 60)),
    [
        'id' => $notifiable->getKey(),
        'hash' => sha1($notifiable->getEmailForVerification()),
    ]
);

// Add this here rather than as a parameter so it doesn't form part of the hash
$url = $url.'&return='.request()->get('return') ?? '';
return $url;

更令人费解的是,如果在验证 URL 中return,那么如果验证就好了。例如这有效:

https://localhost.com/email/verify/287/23e499466a6bad538df7ce48e090294502502a86?expires=1630005974&signature=f77d57494132c71735e744a224e5116974fec33b482ec5874c40ca6321d200e6&return=

编辑:

经过进一步调查后,我发现将返回 URL 添加到签名 URL 生成意味着它只要return不为空就可以工作。如果传递的是空字符串,则在验证时会生成 403。

$url = URL::temporarySignedRoute(
    'verification.verify',
    Carbon::now()->addMinutes(Config::get('auth.verification.expire', 60)),
    [
        'id' => $notifiable->getKey(),
        'hash' => sha1($notifiable->getEmailForVerification()),
        'return' => rtrim(request()->get('return'), '/') ?? '',
    ]
);

return $url;

如果有return值,上述工作正常,否则为 403s。

4

0 回答 0