PM_Console/backend/app/Http/Controllers/Api/AuthController.php

282 خطوط
9.8 KiB
PHP

<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Http\Requests\ChangePasswordRequest;
use App\Http\Requests\LoginRequest;
use App\Http\Requests\UpdateProfileRequest;
use App\Http\Resources\UserResource;
use App\Models\User;
use App\Services\ActivityLogService;
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\Schema;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
class AuthController extends Controller
{
public function __construct(protected ActivityLogService $activityLogService) {}
public function login(LoginRequest $request): JsonResponse
{
try {
$credentials = $request->validated();
$identifier = strtolower(trim($credentials['identifier']));
$user = $this->findUserForLogin($identifier);
if (! $user || ! Hash::check($credentials['password'], $user->password)) {
$this->logAuthEvent(null, 'failed_login', 'تلاش ناموفق ورود', $request, $identifier);
return response()->json([
'success' => false,
'message' => 'نام کاربری یا رمز عبور اشتباه است',
], 401);
}
if ($user->status !== null && $user->status !== 'active') {
$this->logAuthEvent($user->id, 'blocked_login', 'تلاش ورود کاربر غیرفعال', $request, $identifier);
return response()->json([
'success' => false,
'message' => 'امکان ورود با این اطلاعات وجود ندارد',
], 403);
}
$token = $user->createToken('api-token')->plainTextToken;
$user->load(['roles.permissions']);
$this->logAuthEvent($user->id, 'login', 'ورود موفق به سیستم', $request, $identifier);
return response()->json([
'success' => true,
'data' => [
'user' => new UserResource($user),
'token' => $token,
'permissions' => $user->roles->flatMap(function ($role) {
return $role->permissions->pluck('name');
})->unique()->values(),
],
'message' => 'ورود با موفقیت انجام شد',
]);
} catch (\Exception $e) {
Log::error('Login failed unexpectedly', [
'identifier_hash' => isset($identifier) ? hash('sha256', $identifier) : null,
'exception' => $e,
]);
return response()->json([
'success' => false,
'message' => 'خطا در ورود به سیستم',
], 500);
}
}
private function findUserForLogin(string $identifier): ?User
{
$query = User::query()
->whereRaw('LOWER(email) = ?', [$identifier])
->orWhereRaw('LOWER(name) = ?', [$identifier]);
if (Schema::hasColumn('users', 'username')) {
$query->orWhereRaw('LOWER(username) = ?', [$identifier]);
}
$user = $query->orderBy('id')->first();
if ($user || str_contains($identifier, '@')) {
return $user;
}
$emailPrefixMatches = User::query()
->whereRaw('LOWER(email) LIKE ?', [$identifier.'@%'])
->limit(2)
->get();
return $emailPrefixMatches->count() === 1 ? $emailPrefixMatches->first() : null;
}
public function logout(Request $request): JsonResponse
{
try {
$this->logAuthEvent($request->user()?->id, 'logout', 'خروج از سیستم', $request);
$request->user()->currentAccessToken()?->delete();
return response()->json([
'success' => true,
'message' => 'خروج با موفقیت انجام شد',
]);
} catch (\Exception $e) {
return response()->json([
'success' => false,
'message' => 'خطا در خروج از سیستم',
], 500);
}
}
public function user(Request $request): JsonResponse
{
try {
$user = $request->user()->load(['roles.permissions']);
return response()->json([
'success' => true,
'data' => new UserResource($user),
'message' => 'اطلاعات کاربر',
]);
} catch (\Exception $e) {
return response()->json([
'success' => false,
'message' => 'خطا در دریافت اطلاعات کاربر',
], 500);
}
}
public function updateProfile(UpdateProfileRequest $request): JsonResponse
{
try {
$user = $request->user();
$user->update($request->validated());
return response()->json([
'success' => true,
'data' => new UserResource($user->fresh()),
'message' => 'پروفایل با موفقیت به‌روزرسانی شد',
]);
} catch (\Exception $e) {
return response()->json([
'success' => false,
'message' => 'خطا در به‌روزرسانی پروفایل',
], 500);
}
}
public function updateAvatar(Request $request): JsonResponse
{
try {
$request->validate([
'avatar' => 'required|image|mimes:jpg,jpeg,png,webp|max:2048',
]);
$user = $request->user();
if ($user->avatar && $user->avatar !== 'avatars/default.png' && Storage::disk('public')->exists($user->avatar)) {
Storage::disk('public')->delete($user->avatar);
}
$path = $request->file('avatar')->store('avatars', 'public');
$user->update(['avatar' => $path]);
return response()->json([
'success' => true,
'data' => new UserResource($user->fresh()),
'message' => 'عکس پروفایل با موفقیت به‌روزرسانی شد',
]);
} catch (\Exception $e) {
return response()->json([
'success' => false,
'message' => 'خطا در به‌روزرسانی عکس پروفایل',
], 500);
}
}
public function changePassword(ChangePasswordRequest $request): JsonResponse
{
try {
$user = $request->user();
if (! Hash::check($request->current_password, $user->password)) {
return response()->json([
'success' => false,
'message' => 'رمز عبور فعلی اشتباه است',
], 400);
}
$user->update(['password' => Hash::make($request->new_password)]);
$user->tokens()->delete();
return response()->json([
'success' => true,
'message' => 'رمز عبور با موفقیت تغییر یافت',
'reauthentication_required' => true,
]);
} catch (\Exception $e) {
return response()->json([
'success' => false,
'message' => 'خطا در تغییر رمز عبور',
], 500);
}
}
public function forgotPassword(Request $request): JsonResponse
{
$data = $request->validate(['email' => 'required|email']);
Password::sendResetLink(['email' => strtolower($data['email'])]);
return response()->json([
'success' => true,
'message' => 'اگر حسابی با این ایمیل وجود داشته باشد، لینک بازیابی ارسال می‌شود.',
]);
}
public function resetPassword(Request $request): JsonResponse
{
$data = $request->validate([
'token' => 'required|string',
'email' => 'required|email',
'password' => 'required|string|min:12|confirmed',
]);
$status = Password::reset(
$data,
function (User $user, string $password) {
$user->forceFill([
'password' => Hash::make($password),
'remember_token' => Str::random(60),
])->save();
$user->tokens()->delete();
event(new PasswordReset($user));
}
);
if ($status !== Password::PASSWORD_RESET) {
return response()->json([
'success' => false,
'message' => 'توکن بازیابی نامعتبر یا منقضی شده است.',
], 422);
}
return response()->json([
'success' => true,
'message' => 'رمز عبور تغییر کرد. دوباره وارد شوید.',
]);
}
private function logAuthEvent(?int $userId, string $action, string $description, Request $request, ?string $identifier = null): void
{
try {
$properties = [
'ip' => $request->ip(),
'user_agent' => substr((string) $request->userAgent(), 0, 255),
];
if ($identifier) {
$properties['identifier_hash'] = hash('sha256', strtolower($identifier));
}
$this->activityLogService->log($userId, $action, $description, 'auth', $userId, null, null, $properties);
} catch (\Throwable $e) {
Log::warning('Auth activity log failed', [
'user_id' => $userId,
'action' => $action,
'exception' => $e,
]);
}
}
}