Update JWT Token
This commit is contained in:
@@ -16,280 +16,103 @@ use Illuminate\Support\Facades\Validator;
|
|||||||
use Modules\Primaya\Helpers\ApiResponse;
|
use Modules\Primaya\Helpers\ApiResponse;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use App\Helpers\Helper;
|
use App\Helpers\Helper;
|
||||||
|
use App\Models\Corporate;
|
||||||
use Illuminate\Support\Facades\View;
|
use Illuminate\Support\Facades\View;
|
||||||
|
use Tymon\JWTAuth\Facades\JWTAuth;
|
||||||
|
use Tymon\JWTAuth\Exceptions\JWTException;
|
||||||
|
|
||||||
class AuthController extends Controller
|
class AuthController extends Controller
|
||||||
{
|
{
|
||||||
public function login(Request $request)
|
public function loginJwt(Request $request)
|
||||||
{
|
{
|
||||||
$data = [
|
$data = [
|
||||||
'email' => $request->email,
|
'email' => $request->email,
|
||||||
'password' => $request->password
|
'password' => $request->password
|
||||||
];
|
];
|
||||||
|
|
||||||
$validator = Validator::make($request->all(), [
|
$validator = Validator::make($request->all(), [
|
||||||
'email' => 'required|email',
|
'email' => 'required|email',
|
||||||
'password' => 'required'
|
'password' => 'required'
|
||||||
], [
|
|
||||||
'email.required' => trans('Validation.required',['attribute' => 'Email']),
|
|
||||||
'email.email' => trans('Validation.email'),
|
|
||||||
'password.required' => trans('Validation.required',['attribute' => 'Password']),
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if ($validator->fails())
|
if ($validator->fails()) {
|
||||||
{
|
return ApiResponse::apiResponse(
|
||||||
return ApiResponse::apiResponse('Bad Request', $data, $validator->errors(), 400);
|
'Bad Request',
|
||||||
}
|
$data,
|
||||||
else
|
$validator->errors(),
|
||||||
{
|
400
|
||||||
$user = User::where('email', $request->email)->first();
|
);
|
||||||
if (!$user) {
|
|
||||||
return ApiResponse::apiResponse('Not Found', $data, trans('Message.not_found'), 404);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Hash::check($request->password, $user->password)) {
|
|
||||||
return ApiResponse::apiResponse('Bad Request', $data, trans('Message.password'), 400);
|
|
||||||
}
|
|
||||||
|
|
||||||
$res_data = [
|
|
||||||
'user' => $user,
|
|
||||||
'token' => $user->createToken('app')->plainTextToken
|
|
||||||
];
|
|
||||||
|
|
||||||
return ApiResponse::apiResponse("Success", $res_data, trans('Message.success'), 200);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function logout(Request $request)
|
|
||||||
{
|
|
||||||
$request->user()->tokens()->delete();
|
|
||||||
|
|
||||||
return ApiResponse::apiResponse('Success', [], trans('Message.logout'), 200);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function resetPassword(Request $request)
|
|
||||||
{
|
|
||||||
$user = Auth::user();
|
|
||||||
|
|
||||||
$request->validate([
|
|
||||||
'old_password' => 'required',
|
|
||||||
'new_password' => 'required',
|
|
||||||
'confirm_new_password' => 'required'
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (!Hash::check($request['old_password'], $user->password)) {
|
|
||||||
return response(['Message' => 'Password Salah'], 403);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($request["new_password"] != $request["confirm_new_password"]) {
|
// 🔥 1️⃣ Ambil header
|
||||||
return response([
|
$apiKey = $request->header('X-API-KEY');
|
||||||
'Message' => "Password Tidak Sama"
|
$apiSecret = $request->header('X-API-SECRET');
|
||||||
]);
|
|
||||||
|
if (empty($apiKey) || empty($apiSecret)) {
|
||||||
|
return ApiResponse::apiResponse(
|
||||||
|
'Unauthorized',
|
||||||
|
null,
|
||||||
|
'API Key dan Secret wajib diisi',
|
||||||
|
401
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$user->update([
|
// 🔥 2️⃣ Validasi corporate
|
||||||
'password' => Hash::make($request->confirm_new_password),
|
$corporate = Corporate::where('api_key', $apiKey)
|
||||||
]);
|
->where('api_secret', $apiSecret)
|
||||||
return response()->json($user);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function verifyEmail(Request $request)
|
|
||||||
{
|
|
||||||
$data = [
|
|
||||||
'email' => $request->email,
|
|
||||||
];
|
|
||||||
|
|
||||||
$validator = Validator::make($request->all(), [
|
|
||||||
'email' => 'required|email',
|
|
||||||
], [
|
|
||||||
'email.required' => trans('Validation.required',['attribute' => 'Email']),
|
|
||||||
'email.email' => trans('Validation.email'),
|
|
||||||
]);
|
|
||||||
|
|
||||||
if ($validator->fails())
|
|
||||||
{
|
|
||||||
return ApiResponse::apiResponse('Bad Request', $data, $validator->errors(), 400);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$user = User::where('email', $request->email)->first();
|
|
||||||
if (!$user) {
|
|
||||||
return ApiResponse::apiResponse('Not Found', $data, trans('Message.not_found'), 404);
|
|
||||||
}
|
|
||||||
|
|
||||||
//send email
|
|
||||||
// Insert data notifications
|
|
||||||
$emailTo = $request->email;
|
|
||||||
$dataNotif = [
|
|
||||||
'user_id' => $user->id,
|
|
||||||
'email' => $emailTo,
|
|
||||||
'title' => 'Forgot Password',
|
|
||||||
'description' => 'Request forgot password from Hospital Portal',
|
|
||||||
'type' => 1,
|
|
||||||
'isUnRead' => true,
|
|
||||||
'created_by' => auth()->check() ? auth()->user()->id : null,
|
|
||||||
'created_at' => date('Y-m-d H:i:s'),
|
|
||||||
'updated_at' => date('Y-m-d H:i:s'),
|
|
||||||
];
|
|
||||||
$sendNotif = Helper::insertNotification($dataNotif);
|
|
||||||
//Insert data password reset
|
|
||||||
$token = mt_rand(100000, 999999); // Menghasilkan angka acak antara 100000 dan 999999
|
|
||||||
$p_resets = DB::table('password_resets')
|
|
||||||
->insert([
|
|
||||||
'email' => $request->email,
|
|
||||||
'token' => $token,
|
|
||||||
'created_at' => date('Y-m-d H:i:s'),
|
|
||||||
]);
|
|
||||||
// Send Email after insert notifications
|
|
||||||
if($sendNotif && $p_resets)
|
|
||||||
{
|
|
||||||
//send to alarm
|
|
||||||
$nameTo = 'User';
|
|
||||||
$dataEmail = [
|
|
||||||
'email' => $emailTo,
|
|
||||||
'name' => $nameTo,
|
|
||||||
'subject' => 'Request Forgot Password from Hospital Portal Date '. date('Y-m-d H:i:s'),
|
|
||||||
'body' => View::make('email/forgot_password', ['token' => $token])->render(),
|
|
||||||
];
|
|
||||||
Helper::sendEmail($dataEmail);
|
|
||||||
|
|
||||||
$res = DB::table('password_resets')
|
|
||||||
->where('email', '=', $request->email)
|
|
||||||
->where('token', '=', $token)
|
|
||||||
->first();
|
|
||||||
|
|
||||||
return ApiResponse::apiResponse("Success", $res, trans('Message.success'), 200);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return ApiResponse::apiResponse("Internal Server Error", $data, trans('Message.server_error'), 500);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function verifCode(Request $request)
|
|
||||||
{
|
|
||||||
$data = [
|
|
||||||
'email' => $request->email,
|
|
||||||
'token' => $request->token,
|
|
||||||
];
|
|
||||||
|
|
||||||
$validator = Validator::make($request->all(), [
|
|
||||||
'email' => 'required|email',
|
|
||||||
'token' => 'required|numeric',
|
|
||||||
], [
|
|
||||||
'email.required' => trans('Validation.required',['attribute' => 'Email']),
|
|
||||||
'email.email' => trans('Validation.email'),
|
|
||||||
'token.required' => trans('Validation.required',['attribute' => 'Token']),
|
|
||||||
'token.numeric' => trans('Validation.required',['attribute' => 'Code Numeric']),
|
|
||||||
]);
|
|
||||||
|
|
||||||
if ($validator->fails())
|
|
||||||
{
|
|
||||||
return ApiResponse::apiResponse('Bad Request', $data, $validator->errors(), 400);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//Check Time
|
|
||||||
$check = DB::table('password_resets')
|
|
||||||
->where('email', '=', $request->email)
|
|
||||||
->where('token', '=', $request->token)
|
|
||||||
->select('created_at')
|
|
||||||
->first();
|
->first();
|
||||||
|
|
||||||
if($check)
|
if (!$corporate) {
|
||||||
{
|
return ApiResponse::apiResponse(
|
||||||
$created_at = strtotime($check->created_at); // Konversi string waktu ke UNIX timestamp
|
'Unauthorized',
|
||||||
$now = time(); // Waktu sekarang dalam UNIX timestamp
|
null,
|
||||||
|
'Invalid API Key',
|
||||||
// Hitung selisih waktu dalam menit
|
401
|
||||||
$diffInMinutes = ($now - $created_at) / 60;
|
);
|
||||||
|
|
||||||
if ($diffInMinutes > 60) {
|
|
||||||
return ApiResponse::apiResponse('Not Found', $data, trans('Message.token_expired'), 404);
|
|
||||||
} else {
|
|
||||||
// Lanjutkan dengan proses pemulihan kata sandi
|
|
||||||
return ApiResponse::apiResponse("Success", $data, trans('Message.success'), 200);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return ApiResponse::apiResponse('Not Found', $data, trans('Message.not_found'), 404);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public function forgetPassword(Request $request)
|
// 🔥 3️⃣ Cari user sesuai corporate
|
||||||
{
|
$user = User::where('email', $request->email)
|
||||||
$data = [
|
->where('corporate_id', $corporate->id)
|
||||||
'email' => $request->email,
|
|
||||||
'token' => $request->token,
|
|
||||||
'new_password' => $request->new_password
|
|
||||||
];
|
|
||||||
|
|
||||||
$validator = Validator::make($request->all(), [
|
|
||||||
'email' => 'required|email',
|
|
||||||
'token' => 'required|numeric',
|
|
||||||
'new_password' => [
|
|
||||||
'required',
|
|
||||||
'min:8',
|
|
||||||
'regex:/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/'
|
|
||||||
]
|
|
||||||
], [
|
|
||||||
'email.required' => trans('Validation.required',['attribute' => 'Email']),
|
|
||||||
'email.email' => trans('Validation.email'),
|
|
||||||
'token.required' => trans('Validation.required',['attribute' => 'Token']),
|
|
||||||
'new_password.required' => trans('Validation.required',['attribute' => 'New Password']),
|
|
||||||
'new_password.min' => trans('Validation.min',['attribute' => 'New Password']),
|
|
||||||
'new_password.regex' => trans('Validation.regex',['attribute' => 'New Password']),
|
|
||||||
]);
|
|
||||||
|
|
||||||
if($request->new_password != $request->confirm_new_password)
|
|
||||||
{
|
|
||||||
return ApiResponse::apiResponse('Bad Request', $data, 'Confirm password is not the same', 400);
|
|
||||||
}
|
|
||||||
else if ($validator->fails())
|
|
||||||
{
|
|
||||||
return ApiResponse::apiResponse('Bad Request', $data, $validator->errors(), 400);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//Check Time
|
|
||||||
$check = DB::table('password_resets')
|
|
||||||
->where('email', '=', $request->email)
|
|
||||||
->where('token', '=', $request->token)
|
|
||||||
->select('created_at')
|
|
||||||
->first();
|
->first();
|
||||||
|
|
||||||
if($check)
|
if (!$user || !Hash::check($request->password, $user->password)) {
|
||||||
{
|
return ApiResponse::apiResponse(
|
||||||
$created_at = strtotime($check->created_at); // Konversi string waktu ke UNIX timestamp
|
'Unauthorized',
|
||||||
$now = time(); // Waktu sekarang dalam UNIX timestamp
|
$data,
|
||||||
|
'Email atau password salah',
|
||||||
// Hitung selisih waktu dalam menit
|
401
|
||||||
$diffInMinutes = ($now - $created_at) / 60;
|
);
|
||||||
|
|
||||||
if ($diffInMinutes > 60) {
|
|
||||||
return ApiResponse::apiResponse('Not Found', $data, trans('Message.token_expired'), 404);
|
|
||||||
} else {
|
|
||||||
// Lanjutkan dengan proses pemulihan kata sandi
|
|
||||||
$user = User::where('email', $request->email)->first();
|
|
||||||
if ($user)
|
|
||||||
{
|
|
||||||
$newPassword = Hash::make($request->new_password);
|
|
||||||
$user->password = $newPassword;
|
|
||||||
$user->save();
|
|
||||||
return ApiResponse::apiResponse("Success", $data, trans('Message.success'), 200);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return ApiResponse::apiResponse('Not Found', $data, trans('Message.token_expired'), 404);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return ApiResponse::apiResponse('Not Found', $data, trans('Message.not_found'), 404);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 🔥 4️⃣ Generate JWT dengan claim corporate_id
|
||||||
|
$token = auth('corporate-api')->claims([
|
||||||
|
'corporate_id' => $corporate->id
|
||||||
|
])->login($user);
|
||||||
|
|
||||||
|
} catch (JWTException $e) {
|
||||||
|
return ApiResponse::apiResponse(
|
||||||
|
'Error',
|
||||||
|
null,
|
||||||
|
'Gagal membuat token',
|
||||||
|
500
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$res_data = [
|
||||||
|
'user' => $user,
|
||||||
|
'corporate_id' => $corporate->id,
|
||||||
|
'token' => $token,
|
||||||
|
'type' => 'Bearer',
|
||||||
|
'expires_in' => auth('corporate-api')->factory()->getTTL() * 60
|
||||||
|
];
|
||||||
|
|
||||||
|
return ApiResponse::apiResponse(
|
||||||
|
"Success",
|
||||||
|
$res_data,
|
||||||
|
'Login berhasil',
|
||||||
|
200
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,50 +22,40 @@ class Authorization
|
|||||||
$acceptHeader = $request->header('Accept');
|
$acceptHeader = $request->header('Accept');
|
||||||
$contentType = $request->header('Content-Type');
|
$contentType = $request->header('Content-Type');
|
||||||
$locale = $request->header('Accept-Language');
|
$locale = $request->header('Accept-Language');
|
||||||
$authorization = $request->header('Authorization');
|
|
||||||
|
|
||||||
// Add language
|
if (!$locale) {
|
||||||
if(!$locale)
|
return ApiResponse::apiResponse(
|
||||||
{
|
'Unauthorized',
|
||||||
return ApiResponse::apiResponse('Unauthorized', null, trans('Validation.required', ['attribute' => 'Accept-Language']), 401);
|
null,
|
||||||
|
trans('Validation.required', ['attribute' => 'Accept-Language']),
|
||||||
|
401
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if($locale !== 'en-US' && $locale !== 'id-ID')
|
|
||||||
{
|
if ($locale === 'en-US') {
|
||||||
return ApiResponse::apiResponse('Bad Request', null, trans('Validation.invalid', ['attribute' => 'Accept-Language']), 400);
|
|
||||||
}
|
|
||||||
if ($locale === 'en-US')
|
|
||||||
{
|
|
||||||
App::setLocale('en');
|
App::setLocale('en');
|
||||||
} elseif ($locale === 'id-ID')
|
} elseif ($locale === 'id-ID') {
|
||||||
{
|
|
||||||
App::setLocale('id');
|
App::setLocale('id');
|
||||||
} else
|
|
||||||
{
|
|
||||||
App::setLocale('en');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate authorization
|
if ($acceptHeader !== 'application/json') {
|
||||||
if (empty($authorization) || strpos($authorization, 'Bearer ') !== 0) {
|
return ApiResponse::apiResponse(
|
||||||
return ApiResponse::apiResponse('Unauthorized', null, trans('Validation.required', ['attribute' => 'Authorization']), 401);
|
'Bad Request',
|
||||||
|
null,
|
||||||
|
trans('Validation.invalid', ['attribute' => 'Accept']),
|
||||||
|
400
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate type accept & content type
|
if ($request->isMethod('post') && $contentType !== 'application/json') {
|
||||||
if (!$acceptHeader)
|
return ApiResponse::apiResponse(
|
||||||
{
|
'Bad Request',
|
||||||
return ApiResponse::apiResponse('Unauthorized', null, trans('Validation.required', ['attribute' => 'Accept']), 401);
|
null,
|
||||||
}
|
trans('Validation.invalid', ['attribute' => 'Content-Type']),
|
||||||
if (!$contentType && $request->isMethod('post'))
|
400
|
||||||
{
|
);
|
||||||
return ApiResponse::apiResponse('Unauthorized', null, trans('Validation.required', ['attribute' => 'Content-Type']), 401);
|
|
||||||
}
|
|
||||||
if ($acceptHeader !== 'application/json')
|
|
||||||
{
|
|
||||||
return ApiResponse::apiResponse('Bad Request', null, trans('Validation.invalid', ['attribute' => 'Accept']), 400);
|
|
||||||
}
|
|
||||||
if($contentType !== 'application/json' && $request->isMethod('post'))
|
|
||||||
{
|
|
||||||
return ApiResponse::apiResponse('Bad Request', null, trans('Validation.invalid', ['attribute' => 'Content-Type']), 400);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $next($request);
|
return $next($request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
36
Modules/Primaya/Http/Middleware/CheckCorporateKey.php
Normal file
36
Modules/Primaya/Http/Middleware/CheckCorporateKey.php
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Modules\Primaya\Http\Middleware;
|
||||||
|
|
||||||
|
use App\Models\Corporate;
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
|
||||||
|
class CheckCorporateKey
|
||||||
|
{
|
||||||
|
public function handle(Request $request, Closure $next): Response
|
||||||
|
{
|
||||||
|
$apiKey = $request->header('X-API-KEY');
|
||||||
|
$apiSecret = $request->header('X-API-SECRET');
|
||||||
|
|
||||||
|
// 🔥 WAJIB: Cegah null atau kosong
|
||||||
|
if (empty($apiKey) || empty($apiSecret)) {
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'API Key dan Secret wajib diisi'
|
||||||
|
], 401);
|
||||||
|
}
|
||||||
|
|
||||||
|
$corporate = Corporate::where('api_key', $apiKey)
|
||||||
|
->where('api_secret', $apiSecret)
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if (!$corporate) {
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'Invalid API Key'
|
||||||
|
], 401);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,25 +16,24 @@ use Modules\Primaya\Http\Middleware\Authorization;
|
|||||||
| is assigned the "api" middleware group. Enjoy building your API!
|
| is assigned the "api" middleware group. Enjoy building your API!
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
Route::prefix('v1')->group(function() {
|
Route::prefix('v1')->group(function () {
|
||||||
|
|
||||||
Route::prefix('primaya')->group(function () {
|
Route::prefix('primaya')->group(function () {
|
||||||
|
|
||||||
Route::middleware(Authentication::class)->group(function () {
|
// LOGIN (pakai corporate key)
|
||||||
Route::controller(AuthController::class)->group(function () {
|
Route::middleware(['corporate.key'])->group(function () {
|
||||||
Route::post('login', 'login');
|
Route::post('login', [AuthController::class, 'loginJwt']);
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::middleware('auth:sanctum')->group(function () {
|
// JWT Protected
|
||||||
|
Route::middleware(['auth:corporate-api'])->group(function () {
|
||||||
|
|
||||||
Route::middleware(Authorization::class)->group(function () {
|
Route::middleware(Authorization::class)->group(function () {
|
||||||
//Search Member
|
Route::post('search-member', [MemberController::class, 'search']);
|
||||||
Route::controller(MemberController::class)->group(function () {
|
|
||||||
Route::post('search-member', 'search');
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -67,11 +67,12 @@ class Kernel extends HttpKernel
|
|||||||
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
||||||
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
|
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
|
||||||
'linksehat.old.auth' => \App\Http\Middleware\LinksehatOldAuthMiddleware::class,
|
'linksehat.old.auth' => \App\Http\Middleware\LinksehatOldAuthMiddleware::class,
|
||||||
|
'corporate.key' => \Modules\Primaya\Http\Middleware\CheckCorporateKey::class,
|
||||||
|
|
||||||
// Role
|
// Role
|
||||||
'role' => \Spatie\Permission\Middlewares\RoleMiddleware::class,
|
'role' => \Spatie\Permission\Middlewares\RoleMiddleware::class,
|
||||||
'permission' => \Spatie\Permission\Middlewares\PermissionMiddleware::class,
|
'permission' => \Spatie\Permission\Middlewares\PermissionMiddleware::class,
|
||||||
'role_or_permission' => \Spatie\Permission\Middlewares\RoleOrPermissionMiddleware::class,
|
'role_or_permission' => \Spatie\Permission\Middlewares\RoleOrPermissionMiddleware::class,
|
||||||
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,10 +23,19 @@ class Authenticate extends Middleware
|
|||||||
|
|
||||||
public function handle($request, Closure $next, ...$guards)
|
public function handle($request, Closure $next, ...$guards)
|
||||||
{
|
{
|
||||||
if (Auth::guard('sanctum')->guest()) {
|
// Kalau tidak ada guard dikirim dari route
|
||||||
return response()->json(['error' => 'Bearer Authorization is required'], 401);
|
if (empty($guards)) {
|
||||||
|
$guards = [null];
|
||||||
}
|
}
|
||||||
|
|
||||||
return parent::handle($request, $next, ...$guards);
|
foreach ($guards as $guard) {
|
||||||
|
if (Auth::guard($guard)->check()) {
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'error' => 'Unauthorized'
|
||||||
|
], 401);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
use Altek\Accountant\Contracts\Recordable;
|
use Altek\Accountant\Contracts\Recordable;
|
||||||
use App\Traits\Blameable;
|
use App\Traits\Blameable;
|
||||||
use Illuminate\Database\Eloquent\Casts\AsArrayObject;
|
use Illuminate\Database\Eloquent\Casts\AsArrayObject;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
@@ -23,6 +23,8 @@ class Corporate extends Model
|
|||||||
'help_text',
|
'help_text',
|
||||||
'active',
|
'active',
|
||||||
'linking_rules',
|
'linking_rules',
|
||||||
|
'api_key',
|
||||||
|
'api_secret',
|
||||||
'automatic_linking',
|
'automatic_linking',
|
||||||
'phone',
|
'phone',
|
||||||
'phone_alarm_canter',
|
'phone_alarm_canter',
|
||||||
|
|||||||
@@ -11,9 +11,10 @@ use Spatie\Permission\Traits\HasRoles;
|
|||||||
use Spatie\Permission\Models\Role;
|
use Spatie\Permission\Models\Role;
|
||||||
use Spatie\Permission\Models\Permission;
|
use Spatie\Permission\Models\Permission;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Tymon\JWTAuth\Contracts\JWTSubject;
|
||||||
|
|
||||||
|
|
||||||
class User extends Authenticatable
|
class User extends Authenticatable implements JWTSubject
|
||||||
{
|
{
|
||||||
use HasApiTokens, HasFactory, Notifiable, HasRoles;
|
use HasApiTokens, HasFactory, Notifiable, HasRoles;
|
||||||
|
|
||||||
@@ -147,4 +148,14 @@ class User extends Authenticatable
|
|||||||
{
|
{
|
||||||
return $this->notificationTokens()->orderBy('created_at', 'desc')->pluck('token')->toArray();
|
return $this->notificationTokens()->orderBy('created_at', 'desc')->pluck('token')->toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getJWTIdentifier()
|
||||||
|
{
|
||||||
|
return $this->getKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getJWTCustomClaims()
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,10 @@ return [
|
|||||||
'driver' => 'session',
|
'driver' => 'session',
|
||||||
'provider' => 'users',
|
'provider' => 'users',
|
||||||
],
|
],
|
||||||
|
'corporate-api' => [
|
||||||
|
'driver' => 'jwt',
|
||||||
|
'provider' => 'users',
|
||||||
|
],
|
||||||
],
|
],
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
301
config/jwt.php
Normal file
301
config/jwt.php
Normal file
@@ -0,0 +1,301 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of jwt-auth.
|
||||||
|
*
|
||||||
|
* (c) Sean Tymon <tymon148@gmail.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| JWT Authentication Secret
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Don't forget to set this in your .env file, as it will be used to sign
|
||||||
|
| your tokens. A helper command is provided for this:
|
||||||
|
| `php artisan jwt:secret`
|
||||||
|
|
|
||||||
|
| Note: This will be used for Symmetric algorithms only (HMAC),
|
||||||
|
| since RSA and ECDSA use a private/public key combo (See below).
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'secret' => env('JWT_SECRET'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| JWT Authentication Keys
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| The algorithm you are using, will determine whether your tokens are
|
||||||
|
| signed with a random string (defined in `JWT_SECRET`) or using the
|
||||||
|
| following public & private keys.
|
||||||
|
|
|
||||||
|
| Symmetric Algorithms:
|
||||||
|
| HS256, HS384 & HS512 will use `JWT_SECRET`.
|
||||||
|
|
|
||||||
|
| Asymmetric Algorithms:
|
||||||
|
| RS256, RS384 & RS512 / ES256, ES384 & ES512 will use the keys below.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'keys' => [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Public Key
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| A path or resource to your public key.
|
||||||
|
|
|
||||||
|
| E.g. 'file://path/to/public/key'
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'public' => env('JWT_PUBLIC_KEY'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Private Key
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| A path or resource to your private key.
|
||||||
|
|
|
||||||
|
| E.g. 'file://path/to/private/key'
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'private' => env('JWT_PRIVATE_KEY'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Passphrase
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| The passphrase for your private key. Can be null if none set.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'passphrase' => env('JWT_PASSPHRASE'),
|
||||||
|
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| JWT time to live
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Specify the length of time (in minutes) that the token will be valid for.
|
||||||
|
| Defaults to 1 hour.
|
||||||
|
|
|
||||||
|
| You can also set this to null, to yield a never expiring token.
|
||||||
|
| Some people may want this behaviour for e.g. a mobile app.
|
||||||
|
| This is not particularly recommended, so make sure you have appropriate
|
||||||
|
| systems in place to revoke the token if necessary.
|
||||||
|
| Notice: If you set this to null you should remove 'exp' element from 'required_claims' list.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'ttl' => env('JWT_TTL', 60),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Refresh time to live
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Specify the length of time (in minutes) that the token can be refreshed
|
||||||
|
| within. I.E. The user can refresh their token within a 2 week window of
|
||||||
|
| the original token being created until they must re-authenticate.
|
||||||
|
| Defaults to 2 weeks.
|
||||||
|
|
|
||||||
|
| You can also set this to null, to yield an infinite refresh time.
|
||||||
|
| Some may want this instead of never expiring tokens for e.g. a mobile app.
|
||||||
|
| This is not particularly recommended, so make sure you have appropriate
|
||||||
|
| systems in place to revoke the token if necessary.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'refresh_ttl' => env('JWT_REFRESH_TTL', 20160),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| JWT hashing algorithm
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Specify the hashing algorithm that will be used to sign the token.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'algo' => env('JWT_ALGO', Tymon\JWTAuth\Providers\JWT\Provider::ALGO_HS256),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Required Claims
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Specify the required claims that must exist in any token.
|
||||||
|
| A TokenInvalidException will be thrown if any of these claims are not
|
||||||
|
| present in the payload.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'required_claims' => [
|
||||||
|
'iss',
|
||||||
|
'iat',
|
||||||
|
'exp',
|
||||||
|
'nbf',
|
||||||
|
'sub',
|
||||||
|
'jti',
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Persistent Claims
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Specify the claim keys to be persisted when refreshing a token.
|
||||||
|
| `sub` and `iat` will automatically be persisted, in
|
||||||
|
| addition to the these claims.
|
||||||
|
|
|
||||||
|
| Note: If a claim does not exist then it will be ignored.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'persistent_claims' => [
|
||||||
|
// 'foo',
|
||||||
|
// 'bar',
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Lock Subject
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This will determine whether a `prv` claim is automatically added to
|
||||||
|
| the token. The purpose of this is to ensure that if you have multiple
|
||||||
|
| authentication models e.g. `App\User` & `App\OtherPerson`, then we
|
||||||
|
| should prevent one authentication request from impersonating another,
|
||||||
|
| if 2 tokens happen to have the same id across the 2 different models.
|
||||||
|
|
|
||||||
|
| Under specific circumstances, you may want to disable this behaviour
|
||||||
|
| e.g. if you only have one authentication model, then you would save
|
||||||
|
| a little on token size.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'lock_subject' => true,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Leeway
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This property gives the jwt timestamp claims some "leeway".
|
||||||
|
| Meaning that if you have any unavoidable slight clock skew on
|
||||||
|
| any of your servers then this will afford you some level of cushioning.
|
||||||
|
|
|
||||||
|
| This applies to the claims `iat`, `nbf` and `exp`.
|
||||||
|
|
|
||||||
|
| Specify in seconds - only if you know you need it.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'leeway' => env('JWT_LEEWAY', 0),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Blacklist Enabled
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| In order to invalidate tokens, you must have the blacklist enabled.
|
||||||
|
| If you do not want or need this functionality, then set this to false.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'blacklist_enabled' => env('JWT_BLACKLIST_ENABLED', true),
|
||||||
|
|
||||||
|
/*
|
||||||
|
| -------------------------------------------------------------------------
|
||||||
|
| Blacklist Grace Period
|
||||||
|
| -------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| When multiple concurrent requests are made with the same JWT,
|
||||||
|
| it is possible that some of them fail, due to token regeneration
|
||||||
|
| on every request.
|
||||||
|
|
|
||||||
|
| Set grace period in seconds to prevent parallel request failure.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'blacklist_grace_period' => env('JWT_BLACKLIST_GRACE_PERIOD', 0),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Cookies encryption
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| By default Laravel encrypt cookies for security reason.
|
||||||
|
| If you decide to not decrypt cookies, you will have to configure Laravel
|
||||||
|
| to not encrypt your cookie token by adding its name into the $except
|
||||||
|
| array available in the middleware "EncryptCookies" provided by Laravel.
|
||||||
|
| see https://laravel.com/docs/master/responses#cookies-and-encryption
|
||||||
|
| for details.
|
||||||
|
|
|
||||||
|
| Set it to true if you want to decrypt cookies.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'decrypt_cookies' => false,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Providers
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Specify the various providers used throughout the package.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'providers' => [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| JWT Provider
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Specify the provider that is used to create and decode the tokens.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'jwt' => Tymon\JWTAuth\Providers\JWT\Lcobucci::class,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Authentication Provider
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Specify the provider that is used to authenticate users.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'auth' => Tymon\JWTAuth\Providers\Auth\Illuminate::class,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Storage Provider
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Specify the provider that is used to store tokens in the blacklist.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'storage' => Tymon\JWTAuth\Providers\Storage\Illuminate::class,
|
||||||
|
|
||||||
|
],
|
||||||
|
|
||||||
|
];
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
<?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('corporates', function (Blueprint $table) {
|
||||||
|
$table->string('api_key', 64)
|
||||||
|
->unique()
|
||||||
|
->nullable()
|
||||||
|
->after('linking_rules');
|
||||||
|
|
||||||
|
$table->string('api_secret', 128)
|
||||||
|
->nullable()
|
||||||
|
->after('api_key');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('corporates', function (Blueprint $table) {
|
||||||
|
$table->dropColumn(['api_key', 'api_secret']);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user