Cotizaciones/app/Http/Controllers/Api/AuthController.php
2026-04-24 11:19:03 -07:00

345 lines
10 KiB
PHP

<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\ValidationException;
use OpenApi\Attributes as OA;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Cache;
#[OA\Tag(
name: "Auth",
description: "Autenticación de usuarios"
)]
class AuthController extends Controller
{
public function register(Request $request)
{
$request->validate([
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:8|confirmed',
]);
$user = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password),
]);
$token = $user->createToken('auth_token')->plainTextToken;
return response()->json([
'access_token' => $token,
'token_type' => 'Bearer',
]);
}
#[OA\Post(
path: "/api/login_interno",
summary: "Autenticación de usuarios internos",
tags: ["Auth"],
requestBody: new OA\RequestBody(
required: true,
content: new OA\JsonContent(
required: ["email", "password"],
properties: [
new OA\Property(property: "email", type: "string", example: "usuario"),
new OA\Property(property: "password", type: "string", example: "******")
]
)
),
responses: [
new OA\Response(
response: 200,
description: "Login correcto",
content: new OA\JsonContent(
properties: [
new OA\Property(property: "message", type: "string", example: "Login correcto")
]
)
),
new OA\Response(
response: 401,
description: "Credenciales incorrectas",
content: new OA\JsonContent(
properties: [
new OA\Property(property: "message", type: "string", example: "Credenciales incorrectas")
]
)
)
]
)]
public function login_interno(Request $request)
{
try {
$request->validate([
'email' => 'required',
'password' => 'required'
]);
$url = env('SIPA_URL') . '/' . $request->email . '/autenticar';
$response = Http::asForm()->post($url, [
'email' => $request->email,
'password' => $request->password
]);
$status = $response->status();
$body = $response->body();
// Credenciales incorrectas
if ($status === 404 && str_contains($body, '<html')) {
return response()->json(['message' => 'Credenciales incorrectas'], 401);
}
// Invalida token antiguo si existe
$existingToken = Cache::get("sipa_user_token:{$request->email}");
if ($existingToken) {
Cache::forget("sipa_token:{$existingToken}");
}
// Generar token nuevo
$token = bin2hex(random_bytes(32));
// Guardar token en cache (2h)
Cache::put("sipa_token:{$token}", $request->email, 120*60);
Cache::put("sipa_user_token:{$request->email}", $token, 120*60);
// Respuesta SIPA
$data = $response->json() ?: [];
// 🔹 SOLO ESTO SE AGREGA (formato estándar Bearer)
$data['access_token'] = $token;
$data['token_type'] = 'Bearer';
$data['expires_in'] = 120*60;
return response()->json($data, $status);
} catch (\Throwable $e) {
return response()->json([
'message' => 'Error interno',
'error_real' => $e->getMessage()
], 500);
}
}
#[OA\Post(
path: "/api/login_alumno",
summary: "Autenticación de alumnos",
tags: ["Auth"],
requestBody: new OA\RequestBody(
required: true,
content: new OA\JsonContent(
required: ["email", "password"],
properties: [
new OA\Property(property: "email", type: "string", example: "usuario"),
new OA\Property(property: "password", type: "string", example: "******")
]
)
),
responses: [
new OA\Response(
response: 200,
description: "Login correcto",
content: new OA\JsonContent(
properties: [
new OA\Property(property: "message", type: "string", example: "Login correcto")
]
)
),
new OA\Response(
response: 401,
description: "Credenciales incorrectas",
content: new OA\JsonContent(
properties: [
new OA\Property(property: "message", type: "string", example: "Credenciales incorrectas")
]
)
)
]
)]
public function login_alumno(Request $request)
{
$request->validate([
'email' => 'required',
'password' => 'required',
]);
$user = User::where('email', $request->email)->first();
if (! $user || ! Hash::check($request->password, $user->password)) {
throw ValidationException::withMessages([
'email' => ['The provided credentials are incorrect.'],
]);
}
$token = $user->createToken('auth_token')->plainTextToken;
return response()->json([
'access_token' => $token,
'token_type' => 'Bearer',
]);
}
#[OA\Post(
path: "/api/login_externo",
summary: "Autenticación de usuarios externos",
tags: ["Auth"],
requestBody: new OA\RequestBody(
required: true,
content: new OA\JsonContent(
required: ["email", "password"],
properties: [
new OA\Property(property: "email", type: "string", example: "usuario"),
new OA\Property(property: "password", type: "string", example: "******")
]
)
),
responses: [
new OA\Response(
response: 200,
description: "Login correcto",
content: new OA\JsonContent(
properties: [
new OA\Property(property: "message", type: "string", example: "Login correcto")
]
)
),
new OA\Response(
response: 401,
description: "Credenciales incorrectas",
content: new OA\JsonContent(
properties: [
new OA\Property(property: "message", type: "string", example: "Credenciales incorrectas")
]
)
)
]
)]
public function login_externo(Request $request)
{
$request->validate([
'email' => 'required|email',
'password' => 'required',
]);
$user = User::where('email', $request->email)->first();
if (! $user || ! Hash::check($request->password, $user->password)) {
throw ValidationException::withMessages([
'email' => ['The provided credentials are incorrect.'],
]);
}
$token = $user->createToken('auth_token')->plainTextToken;
return response()->json([
'access_token' => $token,
'token_type' => 'Bearer',
]);
}
#[OA\Post(
path: "/api/logout-sipa",
summary: "Cerrar sesión e invalidar token",
security: [["bearerAuth" => []]],
tags: ["Auth"],
responses: [
new OA\Response(
response: 200,
description: "Sesión cerrada",
content: new OA\JsonContent(
properties: [
new OA\Property(property: "message", type: "string", example: "Sesión cerrada correctamente")
]
)
),
new OA\Response(response: 401, description: "Token inválido o no enviado")
]
)]
public function logout_sipa(Request $request)
{
$header = $request->header('Authorization');
if (!$header || !str_starts_with($header, 'Bearer ')) {
return response()->json(['message' => 'Token requerido'], 401);
}
$token = str_replace('Bearer ', '', $header);
$email = Cache::get("sipa_token:{$token}");
if ($email) {
Cache::forget("sipa_token:{$token}");
Cache::forget("sipa_user_token:{$email}");
}
return response()->json([
'message' => 'Sesión cerrada correctamente'
]);
}
#[OA\Post(
path: "/api/refresh-sipa",
summary: "Renovar token",
security: [["bearerAuth" => []]],
tags: ["Auth"],
responses: [
new OA\Response(
response: 200,
description: "Token renovado",
content: new OA\JsonContent(
properties: [
new OA\Property(property: "access_token", type: "string", example: "nuevo_token..."),
new OA\Property(property: "token_type", type: "string", example: "Bearer"),
new OA\Property(property: "expires_in", type: "integer", example: 7200)
]
)
),
new OA\Response(response: 401, description: "Token inválido o expirado")
]
)]
// 🔹 Refresh
public function refresh_sipa(Request $request)
{
$header = $request->header('Authorization');
if (!$header || !str_starts_with($header, 'Bearer ')) {
return response()->json(['message' => 'Token requerido'], 401);
}
$oldToken = str_replace('Bearer ', '', $header);
$email = Cache::get("sipa_token:{$oldToken}");
if (!$email) {
return response()->json(['message' => 'Token inválido o expirado'], 401);
}
Cache::forget("sipa_token:{$oldToken}");
$newToken = bin2hex(random_bytes(32));
$ttl = 120 * 60;
Cache::put("sipa_token:{$newToken}", $email, $ttl);
Cache::put("sipa_user_token:{$email}", $newToken, $ttl);
return response()->json([
'access_token' => $newToken,
'token_type' => 'Bearer',
'expires_in' => $ttl
]);
}
}