简体   繁体   English

Laravel 8 rest api email 验证

[英]Laravel 8 rest api email verification

After a huge search in the inte.net and in the forum, I just gave up...在 inte.net 和论坛中进行了大量搜索后,我放弃了......

I am develping a rest api using Laravel 8 and I am trying since week to make the email verification working using the officiel documentation for that, the email is always sent successfully once the user is registered event(new Registered($user));我正在开发一个 rest api 使用 Laravel 8 我从本周开始尝试使用官方文档进行 email 验证工作,email 总是在用户注册后成功发送event(new Registered($user));
The problem is that once I click on the link in the received email, I got redirected to the login page (which in this case is a post call)..问题是,一旦我点击收到的 email 中的链接,我就会被重定向到登录页面(在这种情况下是一个邮寄电话)。

Here my routes/api.php:这是我的路线/ 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');
});

And here my VerificationController:这里是我的 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);
    }
}

Last but not least, I added the LogVerifiedUser event to EventServiceProvider as required.最后但同样重要的是,我根据需要将 LogVerifiedUser 事件添加到 EventServiceProvider。

Any suggestion plz?有什么建议吗? I tried to remove the middleware auth from verify route, but it doesn't help me...我试图从verify路由中删除中间件auth验证,但它对我没有帮助......

PS : I am using JWT for authentication PS :我正在使用 JWT 进行身份验证

I had to develop exactly the same functionality for my rest laravel 8 api, I share my work with you, hoping to be able to help you.我必须为我的 rest laravel 8 api 开发完全相同的功能,我与您分享我的工作,希望能够帮助您。

To begin, your problem is that the user is redirected to the login page after clicking on the verification link.首先,您的问题是用户在单击验证链接后被重定向到登录页面。 But the question is has the user been marked as verified in the database when he click?但问题是用户点击时是否在数据库中被标记为已验证?

If it is marked as verified in the database after the click, the functionality is working but the problem is the redirection.如果单击后在数据库中标记为已验证,则该功能正在运行,但问题是重定向。 Because if you are using a Rest API you would probably want the user to be redirected to a login or success page of your frontend application.因为如果您使用的是 Rest API 您可能希望将用户重定向到前端应用程序的登录或成功页面。

The last problem is your middleware.最后一个问题是你的中间件。 First in the api.php file the middleware for the connection is 'auth:api' instead of 'auth'.首先在 api.php 文件中,连接的中间件是“auth:api”而不是“auth”。 But for once you do not have to put middleware on the verification route otherwise you will have to have the user connect so that he validates his email and since you go through an API route it is pretty boring...但是一旦你不必将中间件放在验证路径上,否则你将不得不让用户连接,以便他验证他的 email 并且因为你通过 ZDB974238714CA8DE634A7CE1D083A1go 通过 ZDB974238714CA8DE634A7CE1D083A14

Finally here is the solution I opted for:最后,这是我选择的解决方案:

1. In your app/Models/User.php implements MustVerifyEmail (Normally, from what I understood, that you already did, but I prefer to put it in case if other people go through this topic) 1. 在您的 app/Models/User.php 实现 MustVerifyEmail (通常,据我了解,您已经这样做了,但我更愿意将其放在以防其他人 go 通过本主题)

<?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. In your app/Http/Controllers/AuthController.php add event on registered user (Normally, from what I understood, that you already did, but I prefer to put it in case if other people go through this topic) 2. 在您的应用程序/Http/Controllers/AuthController.php 中添加注册用户的事件(通常,据我了解,您已经这样做了,但我更愿意把它放在以防其他人 go 通过本主题)

<?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. In your routes/api.php defines this routes: 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. Create app/Http/Controllers/VerifyEmailController.php 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');
    }
}

Explanations:说明:

With this solution we keep all the operation of checking the official documentation by email.有了这个解决方案,我们保留了 email 检查官方文档的所有操作。 Except that instead of checking if the user is connected to retrieve it and put his email in verified.除了检查用户是否已连接来检索它并将他的 email 放入已验证之外。 We launch a method in a controller which will find the corresponding user to put it in verified.我们在 controller 中启动一个方法,该方法将找到相应的用户进行验证。

I hope I was understandable and that it can help you:)我希望我是可以理解的,它可以帮助你:)

That's because in register() method you don't logged in the user immediately after registering the user, when the user click the link in the email, laravel auth middleware detect that current user who visit the link is not authenticated, so it redirect the user to login route.这是因为在register()方法中注册用户后并没有立即登录用户,当用户点击email中的链接时,laravel auth中间件检测到当前访问该链接的用户未通过身份验证,因此它重定向用户登录路由。 To solve this problem refer to @Matthieu Gelle answer but customizes it as follows:要解决此问题,请参考@Matthieu Gelle的回答,但将其自定义如下:

in step number 2 just add this code在第 2 步中只需添加此代码

Auth::login($user);

below event(new Registered($user));以下event(new Registered($user));

in step 3 use this middleware:在第 3 步中使用此中间件:

->middleware(['auth', 'signed'])->name('verification.verify');

for those who use sanctum:对于那些使用圣所的人:

->middleware(['auth:sanctum', 'signed'])->name('verification.verify');

and change method name from '__invoke' to 'verifyEmail'并将方法名称从'__invoke'更改为'verifyEmail'

in step 4 use this method:在第 4 步中使用此方法:

public function verifyEmail(\Illuminate\Foundation\Auth\EmailVerificationRequest $request)
{
    $request->fulfill();
    return response()->json(['code' => 200, 'message' => "Verified successfully"], 200);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM