From cab40d8162ca3d5c07fd8765b9b9b0056d94d82c Mon Sep 17 00:00:00 2001 From: dogukanoksuz Date: Mon, 23 Oct 2023 21:44:55 +0000 Subject: [PATCH] feature: Password reset api --- app/Console/Kernel.php | 6 +++ app/Http/Controllers/API/AuthController.php | 46 +++++++++++++++++++ app/Providers/AppServiceProvider.php | 7 ++- app/Providers/AuthServiceProvider.php | 1 - config/mail.php | 4 +- ...23_180645_create_password_resets_table.php | 32 +++++++++++++ routes/api.php | 2 + 7 files changed, 93 insertions(+), 5 deletions(-) create mode 100644 database/migrations/2023_10_23_180645_create_password_resets_table.php diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index daff62b62..70c8db7ea 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -56,6 +56,12 @@ protected function schedule(Schedule $schedule) }) ->daily() ->name('Clean Log Tables'); + + // Clear expired password reset tokens every 60 minutes + $schedule + ->command('auth:clear-resets') + ->hourly() + ->name('Clear Expired Password Reset Tokens'); } /** diff --git a/app/Http/Controllers/API/AuthController.php b/app/Http/Controllers/API/AuthController.php index 0e97765a1..64cb81af6 100644 --- a/app/Http/Controllers/API/AuthController.php +++ b/app/Http/Controllers/API/AuthController.php @@ -17,10 +17,12 @@ use App\User; use Carbon\Carbon; use GuzzleHttp\Client; +use Illuminate\Auth\Events\PasswordReset; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Log; +use Illuminate\Support\Facades\Password; use Illuminate\Support\Facades\Validator; use Illuminate\Support\Str; use mervick\aesEverywhere\AES256; @@ -236,6 +238,50 @@ public function forceChangePassword(Request $request) return response()->json(['message' => 'Şifreniz başarıyla değiştirildi.']); } + /** + * Send password reset link + */ + public function sendPasswordResetLink(Request $request) + { + // Check email exists on database laravel validator + validate([ + 'email' => 'required|email|exists:users,email', + ]); + + Password::sendResetLink($request->only('email')); + + return response()->json(['message' => 'Şifre sıfırlama bağlantısı e-posta adresinize gönderildi.']); + } + + /** + * Reset password with token + */ + public function resetPassword(Request $request) + { + $request->validate([ + 'token' => 'required', + 'email' => 'required|email', + 'password' => 'required|min:8|confirmed', + ]); + + $status = Password::reset( + $request->only('email', 'password', 'password_confirmation', 'token'), + function (User $user, string $password) { + $user->forceFill([ + 'password' => Hash::make($password) + ])->setRememberToken(Str::random(60)); + + $user->save(); + + event(new PasswordReset($user)); + } + ); + + return $status === Password::PASSWORD_RESET + ? response()->json(['message' => 'Şifreniz başarıyla değiştirildi.']) + : response()->json(['message' => 'Şifre sıfırlama bağlantısı geçersiz.'], 401); + } + /** * Authenticate using Keycloak */ diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 3c4dde398..d10698a7a 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -3,16 +3,15 @@ namespace App\Providers; use App\Models\Notification; -use App\Models\Permission; use App\Observers\NotificationObserver; use App\Observers\UserObserver; use App\User; use Carbon\Carbon; +use Illuminate\Auth\Notifications\ResetPassword; use Illuminate\Contracts\Http\Kernel; use Illuminate\Database\Eloquent\Relations\Relation; use Illuminate\Pagination\Paginator; use Illuminate\Routing\Router; -use Illuminate\Support\Facades\View; use Illuminate\Support\ServiceProvider; /** @@ -48,6 +47,10 @@ public function boot( \App\Http\Middleware\VerifyCsrfToken::class ); } + + ResetPassword::createUrlUsing(function ($user, string $token) { + return request()->getSchemeAndHttpHost() . '/auth/reset_password?token=' . $token . '&email=' . $user->getEmailForPasswordReset(); + }); } /** diff --git a/app/Providers/AuthServiceProvider.php b/app/Providers/AuthServiceProvider.php index b1499bbda..79d4e9ddf 100644 --- a/app/Providers/AuthServiceProvider.php +++ b/app/Providers/AuthServiceProvider.php @@ -3,7 +3,6 @@ namespace App\Providers; use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider; -use Illuminate\Support\Facades\Gate; /** * Auth Service Provider diff --git a/config/mail.php b/config/mail.php index 2f5cfb422..6bb8bbd95 100644 --- a/config/mail.php +++ b/config/mail.php @@ -55,8 +55,8 @@ */ 'from' => [ - 'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'), - 'name' => env('MAIL_FROM_NAME', 'Example'), + 'address' => env('MAIL_USERNAME') ?: 'destek@liman.dev', + 'name' => env('MAIL_FROM_NAME', 'Liman'), ], /* diff --git a/database/migrations/2023_10_23_180645_create_password_resets_table.php b/database/migrations/2023_10_23_180645_create_password_resets_table.php new file mode 100644 index 000000000..e27845ee3 --- /dev/null +++ b/database/migrations/2023_10_23_180645_create_password_resets_table.php @@ -0,0 +1,32 @@ +string('email')->index(); + $table->string('token')->index(); + $table->timestamp('created_at'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('password_resets'); + } +}; diff --git a/routes/api.php b/routes/api.php index f1b1adb2b..9f2019986 100644 --- a/routes/api.php +++ b/routes/api.php @@ -32,6 +32,8 @@ Route::post('/refresh', [AuthController::class, 'refresh']); Route::get('/user', [AuthController::class, 'userProfile']); Route::post('/change_password', [AuthController::class, 'forceChangePassword']); + Route::post('/forgot_password', [AuthController::class, 'sendPasswordResetLink']); + Route::post('/reset_password', [AuthController::class, 'resetPassword']); }); Route::post('/notifications/send', [ExternalNotificationController::class, 'accept']);