241 خطوط
8.3 KiB
PHP
241 خطوط
8.3 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Http\Requests\LoginRequest;
|
|
use App\Http\Requests\ChangePasswordRequest;
|
|
use App\Http\Requests\UpdateProfileRequest;
|
|
use App\Http\Resources\UserResource;
|
|
use App\Models\User;
|
|
use App\Services\ActivityLogService;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Hash;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Illuminate\Support\Facades\Schema;
|
|
use Illuminate\Support\Facades\Storage;
|
|
|
|
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)]);
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => 'رمز عبور با موفقیت تغییر یافت',
|
|
]);
|
|
} catch (\Exception $e) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => 'خطا در تغییر رمز عبور',
|
|
], 500);
|
|
}
|
|
}
|
|
|
|
public function forgotPassword(Request $request): JsonResponse
|
|
{
|
|
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,
|
|
]);
|
|
}
|
|
}
|
|
}
|