Meningkatkan user experience dengan memberikan pesan error yang lebih spesifik pada proses login: - Menambahkan logika untuk membedakan error "password salah" dan "user tidak ditemukan" - Menggunakan FILTER_VALIDATE_EMAIL untuk mendeteksi apakah input adalah email atau NIK - Mengganti pesan error generik "Email/NIK atau password tidak sesuai" menjadi pesan yang lebih spesifik - Menambahkan validasi untuk mengecek keberadaan user sebelum memberikan pesan error - Memperbaiki struktur pesan error untuk menampilkan error pada field yang tepat (login atau password) - Meningkatkan keamanan dengan tetap mempertahankan rate limiting pada percobaan login yang gagal - Memastikan backward compatibility dengan sistem error handling yang sudah ada
191 lines
6.6 KiB
PHP
191 lines
6.6 KiB
PHP
<?php
|
|
|
|
namespace Modules\Authentication\Http\Requests;
|
|
|
|
use Illuminate\Auth\Events\Lockout;
|
|
use Illuminate\Foundation\Http\FormRequest;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Illuminate\Support\Facades\RateLimiter;
|
|
use Illuminate\Support\Str;
|
|
use Illuminate\Validation\ValidationException;
|
|
use Modules\Basicdata\Models\Branch;
|
|
use Modules\Usermanagement\Models\User;
|
|
|
|
class LoginRequest extends FormRequest
|
|
{
|
|
/**
|
|
* Returns an array of validation rules for the login form.
|
|
*
|
|
* @return array The validation rules.
|
|
*/
|
|
public function rules()
|
|
: array
|
|
{
|
|
return [
|
|
'login' => 'required',
|
|
'password' => 'required',
|
|
];
|
|
}
|
|
|
|
public function messages()
|
|
{
|
|
return [
|
|
'login.required' => 'User tidak boleh kosong',
|
|
'password.required' => 'Password tidak boleh kosong',
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Attempt to authenticate the request's credentials.
|
|
*
|
|
* @return void
|
|
*
|
|
* @throws \Illuminate\Validation\ValidationException
|
|
*/
|
|
public function authenticate(): void
|
|
{
|
|
$this->ensureIsNotRateLimited();
|
|
$credentials = $this->only('login', 'password');
|
|
$loginField = filter_var($credentials['login'], FILTER_VALIDATE_EMAIL) ? 'email' : 'nik';
|
|
$authData = [
|
|
$loginField => $credentials['login'],
|
|
'password' => $credentials['password'],
|
|
];
|
|
|
|
if ($_ENV['METHOD_AUTH'] == 'uim') {
|
|
$this->userIdManagemeent($credentials);
|
|
} else {
|
|
if (!Auth::attempt($authData, $this->boolean('remember'))) {
|
|
RateLimiter::hit($this->throttleKey());
|
|
$loginField = filter_var($credentials['login'], FILTER_VALIDATE_EMAIL) ? 'email' : 'nik';
|
|
$user = User::where($loginField, $credentials['login'])->first();
|
|
|
|
$messages = [];
|
|
if ($user) {
|
|
$messages['password'] = 'Password tidak sesuai';
|
|
} else {
|
|
$messages['login'] = 'Email/NIK tidak ditemukan';
|
|
}
|
|
|
|
throw ValidationException::withMessages($messages);
|
|
}
|
|
|
|
RateLimiter::clear($this->throttleKey());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Authenticate user through user manager
|
|
*
|
|
* @param array $credentials
|
|
* @return \Illuminate\Http\RedirectResponse
|
|
*/
|
|
protected function userIdManagemeent($credentials)
|
|
{
|
|
$userArray = [];
|
|
$id = $credentials['login'];
|
|
$passwd = $credentials['password'];
|
|
$SERVER_ADDR = request()->ip();
|
|
$IPUserManager = $_ENV['IP_USER_MANAGER'];
|
|
$portUserManager = $_ENV['PORT_USER_MANAGER'];
|
|
$appId = $_ENV['APP_ID'];
|
|
|
|
$userData = verify_user($id, $passwd, $SERVER_ADDR, $IPUserManager, $portUserManager, $appId);
|
|
|
|
if (strlen($userData) > 1) {
|
|
$userRawArray = explode("\t", $userData);
|
|
|
|
foreach ($userRawArray as $rval) {
|
|
[$key, $val] = explode('=', $rval);
|
|
$userArray[0][$key] = $val;
|
|
}
|
|
// Use the login value to find the user
|
|
$loginField = filter_var($credentials['login'], FILTER_VALIDATE_EMAIL) ? 'email' : 'nik';
|
|
|
|
$kodeCabang = $userArray[0]['KD_CABANG']; // Example value containing the code
|
|
$lastFourDigits = substr($kodeCabang, -4); // Gets the last 4 characters
|
|
$branch = Branch::where('code', 'LIKE', '%' . $lastFourDigits)->first();
|
|
|
|
session()->put($userArray[0]);
|
|
if ($branch) {
|
|
session()->put('branch_id', $branch->id);
|
|
}
|
|
|
|
$user = User::updateOrCreate(
|
|
[$loginField => $credentials['login']],
|
|
[
|
|
'name' => $userArray[0]['NAMA_USER'],
|
|
'email' => $loginField === 'email' ? $credentials['login'] : null,
|
|
'nik' => $loginField === 'nik' ? $credentials['login'] : null,
|
|
'password' => bcrypt($credentials['password']),
|
|
'branch_id' => $branch ? $branch->id : null,
|
|
]
|
|
);
|
|
|
|
// Assign role based on user group code
|
|
$role = match($userArray[0]['KD_GROUP']) {
|
|
'001' => 'administrator',
|
|
default => 'customer_service'
|
|
};
|
|
|
|
$user->syncRoles($role);
|
|
|
|
Auth::loginUsingId($user->id, true);
|
|
$this->session()->regenerate();
|
|
|
|
RateLimiter::clear($this->throttleKey());
|
|
}
|
|
|
|
// Authentication failed
|
|
RateLimiter::hit($this->throttleKey());
|
|
$loginField = filter_var($credentials['login'], FILTER_VALIDATE_EMAIL) ? 'email' : 'nik';
|
|
$user = User::where($loginField, $credentials['login'])->first();
|
|
|
|
$messages = [];
|
|
if ($user) {
|
|
$messages['password'] = 'Password tidak sesuai';
|
|
} else {
|
|
$messages['login'] = 'Email/NIK tidak ditemukan';
|
|
}
|
|
|
|
throw ValidationException::withMessages($messages);
|
|
}
|
|
|
|
/**
|
|
* Ensure the login request is not rate limited.
|
|
*
|
|
* @return void
|
|
*
|
|
* @throws \Illuminate\Validation\ValidationException
|
|
*/
|
|
public function ensureIsNotRateLimited()
|
|
: void
|
|
{
|
|
if (!RateLimiter::tooManyAttempts($this->throttleKey(), 5)) {
|
|
return;
|
|
}
|
|
|
|
event(new Lockout($this));
|
|
|
|
$seconds = RateLimiter::availableIn($this->throttleKey());
|
|
|
|
throw ValidationException::withMessages([
|
|
'email' => trans('auth.throttle', [
|
|
'seconds' => $seconds,
|
|
'minutes' => ceil($seconds / 60),
|
|
]),
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Get the rate limiting throttle key for the request.
|
|
*
|
|
* @return string
|
|
*/
|
|
public function throttleKey()
|
|
: string
|
|
{
|
|
return Str::transliterate(Str::lower($this->input('email')) . '|' . $this->ip());
|
|
}
|
|
}
|