1-4-Evolución en PHP Puro-Credenciales en Body/Query String:
Evolución en PHP Puro
Antes (Menos Seguro) - Credenciales en Body/Query String:
<?php
// login_old.php - FORMA ANTIGUA (NO RECOMENDADA)
// Credenciales venían en el body (POST) o query string (GET)
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$email = $_POST['email'];
$password = $_POST['password'];
$api_key = $_POST['api_key'] ?? ''; // ❌ MAL: clave en body
// Verificar credenciales
if (authenticateUser($email, $password)) {
session_start();
$_SESSION['user_id'] = getUserId($email);
echo json_encode(['status' => 'success']);
}
}
// O PEOR AÚN - en query string (GET)
// https://api.com/data?api_key=mi_clave_secreta ❌ MUY PELIGROSOAhora (Más Seguro) - Tokens en Headers:
<?php
// api_auth.php - FORMA ACTUAL (RECOMENDADA)
header('Content-Type: application/json');
function getAuthorizationHeader() {
$headers = null;
if (isset($_SERVER['Authorization'])) {
$headers = trim($_SERVER['Authorization']);
} elseif (isset($_SERVER['HTTP_AUTHORIZATION'])) {
$headers = trim($_SERVER['HTTP_AUTHORIZATION']);
} elseif (function_exists('apache_request_headers')) {
$requestHeaders = apache_request_headers();
$requestHeaders = array_combine(
array_map('ucwords', array_keys($requestHeaders)),
array_values($requestHeaders)
);
if (isset($requestHeaders['Authorization'])) {
$headers = trim($requestHeaders['Authorization']);
}
}
return $headers;
}
function getBearerToken() {
$headers = getAuthorizationHeader();
if (!empty($headers)) {
if (preg_match('/Bearer\s(\S+)/', $headers, $matches)) {
return $matches[1];
}
}
return null;
}
// Uso del token desde el header
$token = getBearerToken();
if (!$token) {
http_response_code(401);
echo json_encode(['error' => 'Token no proporcionado']);
exit;
}
// Verificar token
if (verifyToken($token)) {
$userData = decodeToken($token);
echo json_encode(['user' => $userData]);
} else {
http_response_code(401);
echo json_encode(['error' => 'Token inválido']);
}Implementación Completa en PHP Puro
1. Estructura de Archivos:
/api/
├── auth/
│ ├── login.php # Login inicial (body)
│ └── logout.php # Logout (header)
├── users/
│ └── profile.php # Datos usuario (header)
└── config/
├── database.php
└── auth.php2. Configuración de Base de Datos:
<?php
// config/database.php
class Database {
private $host = 'localhost';
private $db_name = 'mi_api';
private $username = 'root';
private $password = '';
public $conn;
public function getConnection() {
$this->conn = null;
try {
$this->conn = new PDO(
"mysql:host=" . $this->host . ";dbname=" . $this->db_name,
$this->username,
$this->password
);
$this->conn->exec("set names utf8");
} catch(PDOException $exception) {
echo "Error de conexión: " . $exception->getMessage();
}
return $this->conn;
}
}3. Sistema de Autenticación:
<?php
// config/auth.php
class Auth {
private $conn;
private $table_name = "users";
public function __construct($db) {
$this->conn = $db;
}
// Login inicial (credenciales en BODY)
public function login($email, $password) {
$query = "SELECT id, name, email, password FROM " . $this->table_name . "
WHERE email = :email LIMIT 1";
$stmt = $this->conn->prepare($query);
$stmt->bindParam(':email', $email);
$stmt->execute();
if ($stmt->rowCount() > 0) {
$row = $stmt->fetch(PDO::FETCH_ASSOC);
$id = $row['id'];
$name = $row['name'];
$email = $row['email'];
$hashed_password = $row['password'];
if (password_verify($password, $hashed_password)) {
// Generar token (simulado - en producción usar JWT)
$token = $this->generateToken($id);
// Guardar token en base de datos
$this->saveToken($id, $token);
return [
'status' => 'success',
'user' => [
'id' => $id,
'name' => $name,
'email' => $email
],
'access_token' => $token,
'token_type' => 'Bearer'
];
}
}
return ['status' => 'error', 'message' => 'Credenciales inválidas'];
}
// Verificar token desde HEADER
public function verifyToken($token) {
$query = "SELECT user_id FROM user_tokens WHERE token = :token AND expires_at > NOW()";
$stmt = $this->conn->prepare($query);
$stmt->bindParam(':token', $token);
$stmt->execute();
if ($stmt->rowCount() > 0) {
$row = $stmt->fetch(PDO::FETCH_ASSOC);
return $row['user_id'];
}
return false;
}
private function generateToken($userId) {
return bin2hex(random_bytes(32)) . '_' . $userId;
}
private function saveToken($userId, $token) {
$query = "INSERT INTO user_tokens (user_id, token, expires_at)
VALUES (:user_id, :token, DATE_ADD(NOW(), INTERVAL 1 HOUR))
ON DUPLICATE KEY UPDATE token = :token, expires_at = DATE_ADD(NOW(), INTERVAL 1 HOUR)";
$stmt = $this->conn->prepare($query);
$stmt->bindParam(':user_id', $userId);
$stmt->bindParam(':token', $token);
return $stmt->execute();
}
}4. Login (Credenciales en BODY):
<?php
// auth/login.php
header('Content-Type: application/json');
require_once '../config/database.php';
require_once '../config/auth.php';
// Permitir CORS si es necesario
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST');
header('Access-Control-Allow-Headers: Content-Type');
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Obtener datos del BODY (JSON)
$input = json_decode(file_get_contents('php://input'), true);
$email = $input['email'] ?? '';
$password = $input['password'] ?? '';
if (!empty($email) && !empty($password)) {
$database = new Database();
$db = $database->getConnection();
$auth = new Auth($db);
$result = $auth->login($email, $password);
if ($result['status'] === 'success') {
// También enviar token en header (buena práctica)
header('Authorization: Bearer ' . $result['access_token']);
http_response_code(200);
echo json_encode($result);
} else {
http_response_code(401);
echo json_encode($result);
}
} else {
http_response_code(400);
echo json_encode(['status' => 'error', 'message' => 'Email y password requeridos']);
}
} else {
http_response_code(405);
echo json_encode(['status' => 'error', 'message' => 'Método no permitido']);
}5. Endpoint Protegido (Token en HEADER):
<?php
// users/profile.php
header('Content-Type: application/json');
require_once '../config/database.php';
require_once '../config/auth.php';
function getBearerToken() {
$headers = null;
if (isset($_SERVER['HTTP_AUTHORIZATION'])) {
$headers = trim($_SERVER['HTTP_AUTHORIZATION']);
} elseif (function_exists('apache_request_headers')) {
$requestHeaders = apache_request_headers();
if (isset($requestHeaders['Authorization'])) {
$headers = trim($requestHeaders['Authorization']);
}
}
if (!empty($headers) && preg_match('/Bearer\s(\S+)/', $headers, $matches)) {
return $matches[1];
}
return null;
}
// Verificar autenticación
$token = getBearerToken();
if (!$token) {
http_response_code(401);
echo json_encode(['error' => 'Token de acceso requerido']);
exit;
}
$database = new Database();
$db = $database->getConnection();
$auth = new Auth($db);
$userId = $auth->verifyToken($token);
if (!$userId) {
http_response_code(401);
echo json_encode(['error' => 'Token inválido o expirado']);
exit;
}
// Token válido - obtener datos del usuario
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
$query = "SELECT id, name, email FROM users WHERE id = :id";
$stmt = $db->prepare($query);
$stmt->bindParam(':id', $userId);
$stmt->execute();
$user = $stmt->fetch(PDO::FETCH_ASSOC);
http_response_code(200);
echo json_encode([
'status' => 'success',
'user' => $user
]);
} else {
http_response_code(405);
echo json_encode(['error' => 'Método no permitido']);
}6. Cliente PHP Consumiendo la API:
<?php
// client_example.php
class ApiClient {
private $base_url = 'http://localhost/api';
private $token = '';
public function login($email, $password) {
$url = $this->base_url . '/auth/login.php';
$data = json_encode([
'email' => $email,
'password' => $password
]);
$response = $this->makeRequest('POST', $url, $data);
if (isset($response['access_token'])) {
$this->token = $response['access_token'];
}
return $response;
}
public function getProfile() {
$url = $this->base_url . '/users/profile.php';
return $this->makeRequest('GET', $url);
}
private function makeRequest($method, $url, $data = null) {
$ch = curl_init();
$headers = [
'Content-Type: application/json',
];
// Agregar token al header si existe
if ($this->token) {
$headers[] = 'Authorization: Bearer ' . $this->token;
}
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
if ($method === 'POST') {
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
}
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return json_decode($response, true);
}
}
// Uso del cliente
$client = new ApiClient();
// Login (credenciales en BODY)
$loginResult = $client->login('usuario@ejemplo.com', 'password123');
if (isset($loginResult['access_token'])) {
// Solicitudes siguientes (token en HEADER)
$profile = $client->getProfile();
print_r($profile);
}Resumen de Flujo en PHP Puro:
Login: Credenciales en
php://input(body) → Genera tokenSolicitudes siguientes: Token en
$_SERVER['HTTP_AUTHORIZATION'](header)Seguridad: Nunca credenciales en URLs o logs
Headers personalizados: Acceder via
$_SERVERoapache_request_headers()
¿Quieres que profundice en algún aspecto específico como JWT en PHP puro o seguridad avanzada?
Comentarios
Publicar un comentario