password reset functionality added
This commit is contained in:
parent
7de44537a0
commit
224657ef44
|
|
@ -2,18 +2,36 @@
|
|||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Mail\ResetPassword;
|
||||
use App\Models\Client;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
|
||||
use Illuminate\Support\Facades\Password;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Auth\Events\PasswordReset;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
/**
|
||||
* @OA\Info(
|
||||
* title="Legalization API",
|
||||
* title="Legalization API - Authorization",
|
||||
* version="1.0.1"
|
||||
* )
|
||||
* @OA\SecurityScheme(
|
||||
* securityScheme="bearerAuth",
|
||||
* in="header",
|
||||
* name="bearerAuth",
|
||||
* type="http",
|
||||
* scheme="bearer",
|
||||
* bearerFormat="JWT",
|
||||
* ),
|
||||
*/
|
||||
|
||||
|
||||
//controller where all auth process for client happens
|
||||
class AuthController extends Controller
|
||||
{
|
||||
|
|
@ -22,7 +40,7 @@ class AuthController extends Controller
|
|||
* @OA\POST(
|
||||
* path="/api/login",
|
||||
* summary=" - Login user",
|
||||
* tags = {"authorization"},
|
||||
* tags = {"Authorization"},
|
||||
* @OA\RequestBody(
|
||||
* @OA\MediaType(
|
||||
* mediaType="application/json",
|
||||
|
|
@ -35,13 +53,13 @@ class AuthController extends Controller
|
|||
* property="password",
|
||||
* type="string",
|
||||
* ),
|
||||
* example={"email": "ilmedovamahri@gmail.com", "password": "Hello001!"}
|
||||
* example={"email": "ilmedovamahri@gmail.com", "password": 12345678}
|
||||
* )
|
||||
* )
|
||||
* ),
|
||||
* @OA\Response(
|
||||
* response="200",
|
||||
* description="Authorization API - LOGIN user"
|
||||
* description="OK"
|
||||
* ),
|
||||
* @OA\Response(
|
||||
* response="401",
|
||||
|
|
@ -49,7 +67,7 @@ class AuthController extends Controller
|
|||
* )
|
||||
* )
|
||||
*/
|
||||
public function login(Request $request){//Login - POST (function to login client from API using Sanctum)
|
||||
public function login(Request $request){
|
||||
$validatedData = request()->validate([
|
||||
'email' => 'required',
|
||||
'password' => 'required|min:6'
|
||||
|
|
@ -77,7 +95,7 @@ public function login(Request $request){//Login - POST (function to login client
|
|||
* @OA\POST(
|
||||
* path="/api/register",
|
||||
* summary=" - Register user",
|
||||
* tags = {"authorization"},
|
||||
* tags = {"Authorization"},
|
||||
* @OA\RequestBody(
|
||||
* @OA\MediaType(
|
||||
* mediaType="application/json",
|
||||
|
|
@ -104,7 +122,7 @@ public function login(Request $request){//Login - POST (function to login client
|
|||
* ),
|
||||
* @OA\Response(
|
||||
* response="200",
|
||||
* description="Authorization API - REGISTER user"
|
||||
* description="OK"
|
||||
* ),
|
||||
* @OA\Response(
|
||||
* response="401",
|
||||
|
|
@ -112,7 +130,7 @@ public function login(Request $request){//Login - POST (function to login client
|
|||
* )
|
||||
* )
|
||||
*/
|
||||
public function register(Request $request){//Register - POST (function to register client from API using Sanctum)
|
||||
public function register(Request $request){
|
||||
$validatedData = request()->validate([
|
||||
'email' => 'required',
|
||||
'password' => 'required|min:6',
|
||||
|
|
@ -146,4 +164,139 @@ public function register(Request $request){//Register - POST (function to regist
|
|||
return response()->json(['success' => ['token' => $tokenResult]], 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* @OA\GET(
|
||||
* path="/api/client",
|
||||
* summary=" - Get user",
|
||||
* tags = {"Authorization"},
|
||||
* security={
|
||||
* {"bearerAuth": {}}
|
||||
* },
|
||||
* @OA\Response(
|
||||
* response="200",
|
||||
* description="OK"
|
||||
* ),
|
||||
* @OA\Response(
|
||||
* response="401",
|
||||
* description="Unauthorized"
|
||||
* )
|
||||
* )
|
||||
*/
|
||||
public function client(Request $request) {
|
||||
$user = $request->user();
|
||||
if($user){
|
||||
return response()->json($request->user(),200);
|
||||
}
|
||||
return response()->json([
|
||||
'message' => 'token_expired'
|
||||
], 401);
|
||||
}
|
||||
|
||||
/**
|
||||
* @OA\POST(
|
||||
* path="/api/logout",
|
||||
* summary=" - Logout user",
|
||||
* tags = {"Authorization"},
|
||||
* security={
|
||||
* {"bearerAuth": {}}
|
||||
* },
|
||||
* @OA\Response(
|
||||
* response="200",
|
||||
* description="OK"
|
||||
* ),
|
||||
* @OA\Response(
|
||||
* response="401",
|
||||
* description="Unauthorized"
|
||||
* )
|
||||
* )
|
||||
*/
|
||||
public function logout(Request $request) {
|
||||
// Revoke the token that was used to authenticate the current request
|
||||
$request->user()->currentAccessToken()->delete();
|
||||
//$request->user->tokens()->delete(); // use this to revoke all tokens (logout from all devices)
|
||||
return response()->json([
|
||||
'message' => 'ok'
|
||||
], 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* @OA\POST(
|
||||
* path="/api/forgot-password",
|
||||
* summary=" - Send a user password reset link",
|
||||
* tags = {"Authorization"},
|
||||
* @OA\RequestBody(
|
||||
* @OA\MediaType(
|
||||
* mediaType="application/json",
|
||||
* @OA\Schema(
|
||||
* @OA\Property(
|
||||
* property="email",
|
||||
* type="string",
|
||||
* ),
|
||||
* example={"email": "ilmedovamahri@gmail.com"}
|
||||
* )
|
||||
* )
|
||||
* ),
|
||||
* @OA\Response(
|
||||
* response="200",
|
||||
* description="OK"
|
||||
* )
|
||||
* )
|
||||
*/
|
||||
public function sendPasswordResetLinkEmail(Request $request) {
|
||||
$request->validate(['email' => 'required|email']);
|
||||
|
||||
$user = Client::where('email', $request->email)->first();
|
||||
if (!$user) {
|
||||
return back()->with('failed', 'Failed! email is not registered.');
|
||||
}
|
||||
|
||||
$token = Str::random(60);
|
||||
|
||||
$user['token'] = $token;
|
||||
$user['is_verified'] = 0;
|
||||
$user->save();
|
||||
|
||||
Mail::to($request->email)->send(new ResetPassword($user->name, $token));
|
||||
|
||||
return response()->json([
|
||||
'message' => 'OK'
|
||||
], 200);
|
||||
}
|
||||
|
||||
public function forgotPasswordValidate($token)
|
||||
{
|
||||
$user = Client::where('token', $token)->where('is_verified', 0)->first();
|
||||
if ($user) {
|
||||
$email = $user->email;
|
||||
return response()->json([
|
||||
'message' => compact('email')
|
||||
]);
|
||||
}
|
||||
return response()->json([
|
||||
'message' => 'token_expired'
|
||||
], 419);
|
||||
}
|
||||
|
||||
public function updatePassword(Request $request) {
|
||||
$this->validate($request, [
|
||||
'email' => 'required',
|
||||
'password' => 'required|min:6',
|
||||
'confirm_password' => 'required|same:password'
|
||||
]);
|
||||
|
||||
$user = Client::where('email', $request->email)->first();
|
||||
if ($user) {
|
||||
$user['is_verified'] = 0;
|
||||
$user['token'] = '';
|
||||
$user['password'] = Hash::make($request->password);
|
||||
$user->save();
|
||||
return response()->json([
|
||||
'message' => 'OK'
|
||||
], 200);
|
||||
}
|
||||
return response()->json([
|
||||
'message' => 'not_found'
|
||||
], 404);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
namespace App\Mail;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class ResetPassword extends Mailable
|
||||
{
|
||||
use Queueable, SerializesModels;
|
||||
|
||||
/**
|
||||
* Create a new message instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
public $name;
|
||||
public $token;
|
||||
|
||||
public function __construct($name, $token)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->token = $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the message.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function build()
|
||||
{
|
||||
$user['name'] = $this->name;
|
||||
$user['token'] = $this->token;
|
||||
|
||||
return $this->from("milmedova96@gmail.com", "Mahri Ilmedova")
|
||||
->subject('Password Reset Link')
|
||||
->view('emails.reset-password', ['user' => $user]);
|
||||
}
|
||||
}
|
||||
|
|
@ -37,6 +37,9 @@ class Client extends Authenticatable
|
|||
| FUNCTIONS
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
public function sendPasswordResetNotification($token){
|
||||
$this->notify(new \App\Notifications\MailResetPasswordNotification($token));
|
||||
}
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
namespace App\Notifications;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
//custom
|
||||
use Illuminate\Support\Facades\Lang;
|
||||
use Illuminate\Auth\Notifications\ResetPassword;
|
||||
|
||||
|
||||
class MailResetPasswordNotification extends Notification{
|
||||
use Queueable;
|
||||
protected $pageUrl;
|
||||
public $token;
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(){
|
||||
parent::__construct($token);
|
||||
$this->pageUrl = 'localhost:8080';
|
||||
}
|
||||
public function via($notifiable){
|
||||
return ['mail'];
|
||||
}
|
||||
public function toMail($notifiable){
|
||||
if(static::$toMailCallback) {
|
||||
return call_user_func(static::$toMailCallback, $notifiable, $this->token);
|
||||
}
|
||||
return (new MailMessage)
|
||||
->subject(Lang::getFromJson('Reset application Password v1'))
|
||||
->line(Lang::getFromJson('You are receiving this email because we received a password reset request for your account.'))
|
||||
->action(Lang::getFromJson('Reset Password'), $this->pageUrl."?token=".$this->token)
|
||||
->line(Lang::getFromJson('This password reset link will expire in :count minutes.', ['count' => config('auth.passwords.users.expire')]))
|
||||
->line(Lang::getFromJson('If you did not request a password reset, no further action is required.'));
|
||||
}
|
||||
}
|
||||
|
|
@ -97,7 +97,7 @@
|
|||
|
||||
'passwords' => [
|
||||
'users' => [
|
||||
'provider' => 'users',
|
||||
'provider' => 'clients',
|
||||
'table' => 'password_resets',
|
||||
'expire' => 60,
|
||||
'throttle' => 60,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('clients', function (Blueprint $table) {
|
||||
$table->string('token')->nullable();
|
||||
$table->boolean('is_verified')->default(0);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('clients', function (Blueprint $table) {
|
||||
//
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:o="urn:schemas-microsoft-com:office:office">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<meta name="x-apple-disable-message-reformatting">
|
||||
<title></title>
|
||||
<style>
|
||||
table,
|
||||
td,
|
||||
div,
|
||||
h1,
|
||||
p {
|
||||
font-weight: 500;
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
.btn {margin: 10px 0px;
|
||||
border-radius: 4px;
|
||||
text-decoration: none;
|
||||
color: #fff !important;
|
||||
height: 46px;
|
||||
padding: 10px 20px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
background-image: linear-gradient(to right top, #021d68, #052579, #072d8b, #09369d, #093fb0) !important;
|
||||
}
|
||||
.btn:hover {
|
||||
text-decoration: none;
|
||||
opacity: .8;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body style="margin:0;padding:0;">
|
||||
<table role="presentation"
|
||||
style="width:100%;border-collapse:collapse;border:0;border-spacing:0;background:#ffffff;">
|
||||
<tr>
|
||||
<td align="center" style="padding:0;">
|
||||
<table role="presentation"
|
||||
style="width:600px;border-collapse:collapse;border:1px solid #cccccc;border-spacing:0;text-align:left;">
|
||||
<tr style="border-collapse:collapse;border:1px solid #cccccc;border-spacing:0;">
|
||||
<td align="left" style="padding:10px 25px;background:#fff; display: flex; align-items: center;">
|
||||
<span style="font-weight: bold; padding-top: 10px;"> Programming Fields </span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding:36px 30px 42px 30px;">
|
||||
<table role="presentation"
|
||||
style="width:100%;border-collapse:collapse;border:0;border-spacing:0;">
|
||||
<tr>
|
||||
<td style="padding:0 0 36px 0;color:#153643;">
|
||||
<p style="font-weight:bold;margin:0 0 20px 0;font-family:Arial,sans-serif;">
|
||||
Hello {{ $user ? $user['name'] : '' }},</h1>
|
||||
<p
|
||||
style="margin:0 0 12px 0;font-size:14px;line-height:24px;font-family:Arial,sans-serif;">
|
||||
We've received a request to reset the password.
|
||||
</p>
|
||||
<p
|
||||
style="margin:10px 0 12px 0;font-size:14px;line-height:24px;font-family:Arial,sans-serif;">
|
||||
You can reset your password by clicking the button below:
|
||||
</p>
|
||||
|
||||
<p style="text-align: center;">
|
||||
<a href="{{'http://localhost:8000/forgot-password/'.$user['token']}}" class="btn">Reset your password</a>
|
||||
</p>
|
||||
|
||||
|
||||
<p style="margin:100px 0 12px 0;font-size:14px;font-family:Arial,sans-serif;">
|
||||
Thank
|
||||
you, </p>
|
||||
<p style="margin:0 0 12px 0;font-size:14px;font-family:Arial,sans-serif;">
|
||||
Programming Fields </p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -22,10 +22,11 @@
|
|||
|
||||
Route::post('/register', [AuthController::class, 'register']);
|
||||
Route::post('/login', [AuthController::class, 'login']);
|
||||
|
||||
Route::post('/forgot-password', [AuthController::class, 'sendPasswordResetLinkEmail'])->name('passwords.sent');
|
||||
Route::post('/reset', [AuthController::class, 'sendResetResponse'])->name('passwords.reset');
|
||||
Route::get('/forgot-password/{token}', [AuthController::class, 'forgotPasswordValidate']);
|
||||
|
||||
Route::middleware(['auth.client','auth:api'])->group(function () {
|
||||
Route::get('/client', function (Request $request) {
|
||||
return $request->user();
|
||||
});
|
||||
Route::get('/client', [AuthController::class, 'client']);
|
||||
Route::post('/logout', [AuthController::class, 'logout']);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
{
|
||||
"openapi": "3.0.0",
|
||||
"info": {
|
||||
"title": "Legalization API",
|
||||
"title": "Legalization API - Authorization",
|
||||
"version": "1.0.1"
|
||||
},
|
||||
"paths": {
|
||||
"/api/login": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"authorization"
|
||||
"Authorization"
|
||||
],
|
||||
"summary": " - Login user",
|
||||
"operationId": "a3b306d14572d1f4bd6c064b3233e7b8",
|
||||
|
|
@ -27,7 +27,7 @@
|
|||
"type": "object",
|
||||
"example": {
|
||||
"email": "ilmedovamahri@gmail.com",
|
||||
"password": "Hello001!"
|
||||
"password": 12345678
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -35,7 +35,7 @@
|
|||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Authorization API - LOGIN user"
|
||||
"description": "OK"
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized"
|
||||
|
|
@ -46,7 +46,7 @@
|
|||
"/api/register": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"authorization"
|
||||
"Authorization"
|
||||
],
|
||||
"summary": " - Register user",
|
||||
"operationId": "8a56853624e025573120a09a4c75d468",
|
||||
|
|
@ -81,13 +81,99 @@
|
|||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Authorization API - REGISTER user"
|
||||
"description": "OK"
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/client": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Authorization"
|
||||
],
|
||||
"summary": " - Get user",
|
||||
"operationId": "9f1c53ceee113e04ff7709c819ce9bf5",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized"
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"bearerAuth": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/api/logout": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"Authorization"
|
||||
],
|
||||
"summary": " - Logout user",
|
||||
"operationId": "fe8f3429cd6979b3b4517e186505f9f9",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized"
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"bearerAuth": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/api/forgot-password": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"Authorization"
|
||||
],
|
||||
"summary": " - Send a user password reset link",
|
||||
"operationId": "45bf57623119762aa1c685aff5d3716e",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"properties": {
|
||||
"email": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"example": {
|
||||
"email": "ilmedovamahri@gmail.com"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"securitySchemes": {
|
||||
"bearerAuth": {
|
||||
"type": "http",
|
||||
"name": "bearerAuth",
|
||||
"in": "header",
|
||||
"bearerFormat": "JWT",
|
||||
"scheme": "bearer"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue