Laravel8restapi邮件验证
在互联网和论坛上进行了大量搜索之后,我只是放弃了......
我正在使用 Laravel 8 开发一个休息 api,并且我从一周开始就尝试使用官方文档进行电子邮件验证,电子邮件是用户注册后总是成功发送event(new Registered($user));
问题是,一旦我点击收到的电子邮件中的链接,我就会被重定向到登录页面(在这种情况下是一个帖子调用)。
这里是我的路由/api.php:
Route::group(['namespace' => 'AppHttpControllers', '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' => 'AppHttpControllers', '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 AppHttpControllers;
use AppHttpControllersController;
use IlluminateHttpRequest;
use IlluminateFoundationAuthEmailVerificationRequest;
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。
lz有什么建议吗?我试图auth从verify路由中删除中间件,但它对我没有帮助...
PS:我正在使用 JWT 进行身份验证
回答
我不得不为我的rest laravel 8 api开发完全相同的功能,我与您分享我的工作,希望能够帮助您。
首先,您的问题是用户在单击验证链接后被重定向到登录页面。但问题是用户在点击时是否在数据库中被标记为已验证?
如果单击后在数据库中将其标记为已验证,则该功能正在运行,但问题在于重定向。因为如果您使用的是 Rest API,您可能希望用户被重定向到前端应用程序的登录或成功页面。
最后一个问题是你的中间件。首先在 api.php 文件中,连接的中间件是“auth:api”而不是“auth”。但是有一次你不必在验证路由上放置中间件,否则你将不得不让用户连接以便他验证他的电子邮件,并且由于你通过 API 路由它很无聊......
最后这是我选择的解决方案:
1. 在你的 app/Models/User.php 中实现 MustVerifyEmail(通常,据我所知,你已经这样做了,但我更愿意把它放在以防其他人经历这个话题)
<?php
namespace AppModels;
use IlluminateContractsAuthMustVerifyEmail;
use IlluminateDatabaseEloquentFactoriesHasFactory;
use IlluminateFoundationAuthUser as Authenticatable;
use IlluminateNotificationsNotifiable;
use LaravelPassportHasApiTokens;
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 AppHttpControllers;
use AppModelsUser;
use IlluminateHttpRequest;
use IlluminateAuthEventsRegistered;
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 AppHttpControllers;
use IlluminateAuthEventsVerified;
use IlluminateHttpRedirectResponse;
use IlluminateHttpRequest;
use IlluminateRoutingController;
use AppModelsUser;
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');
}
}
说明:
有了这个解决方案,我们保留了通过电子邮件查看官方文档的所有操作。除了检查用户是否已连接以检索它并将其电子邮件放入已验证状态之外。我们在控制器中启动一个方法,它会找到相应的用户来验证。
我希望我是可以理解的,它可以帮助你:)