适用于Vue SPA的Laravel电子邮件验证

时间:2019-08-08 14:16:35

标签: laravel email vue.js single-page-application email-verification

如何使用Vue路由器在Vue SPA上实施Laravel的电子邮件验证?

到目前为止,我已经尝试通过更改VerificationController的verify和resend方法来处理电子邮件验证。然后,我创建了一个新通知并为验证添加了API路由。

生成验证链接并将其发送到用户的电子邮件时,验证URL类似于:

https://foobar.test/email/verify/1?expires=1565276056&signature=b15ccd7d6198bdcf81eea4f5cb441efe8eb2d6d5b57a1ce0b1171e685613d917

单击链接后,它会打开一个页面,但由于未点击@verify api路由,因此在后端没有任何作用。

有什么建议吗?

VerificationController.php

Dim MyWb As Workbook
Set MyWb = Workbooks.Open(Filename:="U:\a.xlsx", ReadOnly:=True) 'readonly if you only need to read

'read the value
Debug.Print MyWb.Worksheets("a").Range("A2")

'close it after reading
MyWb.Close SaveChanges:=False

VerifyEmail.php

'open a new hidden Excel
Dim ExApp As Excel.Application
Set ExApp = New Excel.Application 
ExApp.Visible = False

'open the workbook in that hidden ExApp
Dim MyWb As Workbook
Set MyWb = ExApp.Workbooks.Open(Filename:="U:\a.xlsx", ReadOnly:=True)

'read the value
Debug.Print MyWb.Worksheets("a").Range("A2")

'close it after reading
MyWb.Close SaveChanges:=False

'close hidden Excel
ExApp.Quit

Api.php

<?php

namespace App\Http\Controllers\Auth;

use App\User;
use Illuminate\Http\Request;

use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\VerifiesEmails;
use Illuminate\Validation\ValidationException;


class VerificationController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Email Verification Controller
    |--------------------------------------------------------------------------
    |
    | This controller is responsible for handling email verification for any
    | user that recently registered with the application. Emails may also
    | be re-sent if the user didn't receive the original email message.
    |
    */

    use VerifiesEmails;

    /**
     * Where to redirect users after verification.
     *
     * @var string
     */
    protected $redirectTo = '/home';

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('auth:api');
        $this->middleware('signed')->only('verify');
        $this->middleware('throttle:600,1')->only('verify', 'resend');
    }

    /**
     * Show the email verification notice.
     *
     */
    public function show()
    {
        //
    }

    /**
     * Mark the authenticated user's email address as verified.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function verify(Request $request)
    {
      $userID = $request[‘id’];
      $user = User::findOrFail($userID);
      $user->email_verified_at = date("Y-m-d g:i:s");
      $user->save();

      return response()->json('Email verified!');
    }

    /**
     * Resend the email verification notification.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function resend(Request $request)
    {
        if ($request->user()->hasVerifiedEmail()) {
            return response()->json('The email is already verified.', 422);
        }

        $request->user()->sendEmailVerificationNotification();

        return response()->json('We have e-mailed your verification link!');
    }


}

2 个答案:

答案 0 :(得分:0)

我的角度SPA遇到了同样的问题。不确定您是否仍需要帮助,但希望我的回答对您有所帮助。

因此,尽管laravel UrlGenerator::signedRoute不够灵活(您可以订阅此idea。虽然情况不同,但与此相关),我们必须自己实现url签名。

在您的VerifyEmail班上:

    protected function verificationUrl($notifiable)
    {
        // collect and sort url params
        $params = [
            'expires' => Carbon::now()
                ->addMinutes(Config::get('auth.verification.expire', 60))
                ->getTimestamp(),
            'id' => $notifiable->getKey(),
            'hash' => sha1($notifiable->getEmailForVerification()),
        ];
        ksort($params);

        // then create API url for verification. my API have `/api` prefix,
        // so i don't want to show that url to users 
        $url = URL::route(
            'api:auth:verify',
            $params,
            true
        );

        // get APP_KEY from config and create signature
        $key = config('app.key');
        $signature = hash_hmac('sha256', $url, $key);

        // generate url for yous SPA page to send it to user
        return url('verify-email') . '?' . http_build_query($params + compact('signature'), false);
    }

在那之后,您应该在SPA中获取url参数并调用API请求。我将指定Angular示例,但应使其易于适应Vue。

// on component load
ngOnInit() {

  // get query params from current route   
  this.route.queryParamMap.subscribe(params => {

    // generate API url. Make sure your query params come in the same order
    // as in signature generation. By default signature check middleware 
    // extracts `signature` param so `expires` is the only param that
    // is checked so order doesn't matter, but if you need another params -
    // it can turn into a problem 
    const url = this.router.createUrlTree(['api', 'auth', 'verify', data.id, data.hash],
      {queryParams: {expires: data.expires, signature: data.signature}}).toString();

    // make API request. if signature check fails - you will receive 403 error
    return this.http.get(url).subscribe();
  });
}

我看到的另一种更简单的方法是生成直接的API url,然后像您一样将其发送给用户。验证之后,只需将浏览器重定向到您的SPA。我只是不明白为什么它在您的情况下不起作用。也许您的网络服务器配置中有一些重写规则,因此您的实际域名与APP_URL不匹配?或者,也许您在另一个端口中提供API?

答案 1 :(得分:0)

解决方案非常简单。 使用temporarySignedRoute,您需要指定路由,默认值为verification.verify,到期时间和参数。

<?php

namespace App\Notifications;

use Illuminate\Notifications\Notification;


use Illuminate\Support\Facades\URL;
use Carbon\Carbon;


use Illuminate\Auth\Notifications\VerifyEmail as VerifyEmailBase;


class VerifyEmail extends VerifyEmailBase
{

    /**
     * Get the verification URL for the given notifiable.
     *
     * @param  mixed  $notifiable
     * @return string
     */
    protected function verificationUrl($notifiable)
    {
      return URL::temporarySignedRoute(
          'verification.verify',
           now()->addMinutes(60),
           ['id' => $notifiable->id, 'hash' => sha1($notifiable->getEmailForVerification())]
    );

    }
}