首页 > 解决方案 > Laravel 8 rest api 电子邮件验证

问题描述

在互联网和论坛中进行了大量搜索之后,我放弃了......

我正在使用 Laravel 8 开发一个休息 api,并且我从一周开始尝试使用官方文档进行电子邮件验证,电子邮件是一旦用户注册,总是成功发送event(new Registered($user));
问题是,一旦我点击收到的电子邮件中的链接,我就会被重定向到登录页面(在这种情况下是一个帖子调用)。

这里是我的路由/api.php:

Route::group(['namespace' => 'App\Http\Controllers', 'middleware' => ['api'], 'prefix' => 'auth'], function ($router) {
    Route::post('login', 'AuthController@login')->name('login');
    Route::post('register', 'AuthController@register');
    Route::post('logout', 'AuthController@logout');
    Route::post('profile', 'AuthController@profile')->middleware('verified');
    Route::post('refresh', 'AuthController@refresh');
});

Route::group(['namespace' => 'App\Http\Controllers', 'middleware' => ['api']],function ($router) {
    Route::get('/email/verify/{id}/{hash}', 'VerificationController@verify')->middleware(['auth', 'signed'])->name('verification.verify');
    Route::get('/email/resend', 'VerificationController@resend')->middleware(['auth', 'throttle:6,1'])->name('verification.send');
});

这里是我的 VerificationController:

<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Foundation\Auth\EmailVerificationRequest;

class VerificationController extends Controller
{
    public function resend(Request $request)
    {
        $request->user()->sendEmailVerificationNotification();
        return response()->json(['message' => __('auth.email_sent')], Response::HTTP_NO_CONTENT);
    }

    public function verify(EmailVerificationRequest $request)
    {
        $request->fulfill();
        return response()->json(['message' => __('auth.user_verified_successfully')], Response::HTTP_RESET_CONTENT);
    }
}

最后但同样重要的是,我根据需要将 LogVerifiedUser 事件添加到 EventServiceProvider 中。

有什么建议吗?我试图authverify路由中删除中间件,但这对我没有帮助......

PS:我正在使用 JWT 进行身份验证

标签: phplaravellaravel-8email-verification

解决方案


我必须为我的其余 laravel 8 api 开发完全相同的功能,我与你分享我的工作,希望能够帮助你。

首先,您的问题是用户在单击验证链接后被重定向到登录页面。但问题是用户点击时是否在数据库中被标记为已验证?

如果单击后在数据库中标记为已验证,则该功能正在运行,但问题是重定向。因为如果您使用的是 Rest API,您可能希望将用户重定向到前端应用程序的登录或成功页面。

最后一个问题是你的中间件。首先在 api.php 文件中,连接的中间件是 'auth:api' 而不是 'auth'。但是一旦您不必将中间件放在验证路线上,否则您将不得不让用户连接,以便他验证他的电子邮件,并且由于您通过 API 路线,这很无聊......

最后这是我选择的解决方案:

1. 在你的 app/Models/User.php 中实现 MustVerifyEmail(通常,据我了解,你已经这样做了,但我更愿意把它放在以防其他人通过这个主题)

<?php

namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Passport\HasApiTokens;

class User extends Authenticatable implements MustVerifyEmail
{
    use HasFactory, Notifiable, HasApiTokens;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name',
        'email',
        'password',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];

    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];
}

2. 在您的 app/Http/Controllers/AuthController.php 中添加注册用户的事件(通常,据我了解,您已经这样做了,但我更愿意把它放在以防其他人通过这个主题)

<?php

namespace App\Http\Controllers;

use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Auth\Events\Registered;

class AuthController extends Controller
{
    public function register(Request $request)
    {
        $validatedData = $request->validate([
            'name' => 'required|max:55',
            'email' => 'email|required|unique:users',
            'password' => 'required|confirmed'
        ]);

        $validatedData['password'] = bcrypt($request->password);

        $user = User::create($validatedData);

        event(new Registered($user));

        $accessToken = $user->createToken('authToken')->accessToken;

        return response(['user' => $user, 'access_token' => $accessToken]);
    }

    public function login(Request $request)
    {
        $loginData = $request->validate([
            'email' => 'email|required',
            'password' => 'required'
        ]);

        if (!auth()->attempt($loginData)) {
            return response(['message' => 'Invalid Credentials']);
        }

        $accessToken = auth()->user()->createToken('authToken')->accessToken;

        return response(['user' => auth()->user(), 'access_token' => $accessToken]);
    }
}

3. 在你的 routes/api.php 中定义了这个路由:


// Verify email
Route::get('/email/verify/{id}/{hash}', [VerifyEmailController::class, '__invoke'])
    ->middleware(['signed', 'throttle:6,1'])
    ->name('verification.verify');

// Resend link to verify email
Route::post('/email/verify/resend', function (Request $request) {
    $request->user()->sendEmailVerificationNotification();
    return back()->with('message', 'Verification link sent!');
})->middleware(['auth:api', 'throttle:6,1'])->name('verification.send');

4.创建app/Http/Controllers/VerifyEmailController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Auth\Events\Verified;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use App\Models\User;

class VerifyEmailController extends Controller
{

    public function __invoke(Request $request): RedirectResponse
    {
        $user = User::find($request->route('id'));

        if ($user->hasVerifiedEmail()) {
            return redirect(env('FRONT_URL') . '/email/verify/already-success');
        }

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

        return redirect(env('FRONT_URL') . '/email/verify/success');
    }
}

说明:

通过这个解决方案,我们保留了通过电子邮件检查官方文档的所有操作。除了检查用户是否已连接来检索它并将他的电子邮件放入已验证之外。我们在控制器中启动一个方法,该方法将找到相应的用户进行验证。

我希望我是可以理解的,它可以帮助你:)


推荐阅读