Przeglądaj źródła

Implementación de middleware para inicios de sesión

Jose Brito 3 lat temu
rodzic
commit
6eb692a781

+ 11 - 0
sistema-mantenimiento-back/app/Exceptions/Handler.php

@@ -3,6 +3,7 @@
 namespace App\Exceptions;
 
 use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
+use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
 use Throwable;
 
 class Handler extends ExceptionHandler
@@ -37,5 +38,15 @@ class Handler extends ExceptionHandler
         $this->reportable(function (Throwable $e) {
             //
         });
+
+        $this->renderable(function (MethodNotAllowedHttpException $e, $request){
+            $respuesta = json_encode([
+                "error" => true,
+                "msg" => "ERR_GLB_USU000: Método no soportado.",
+                "response" => []
+            ]);
+    
+            return response($respuesta, 405)->header('Content-Type', 'application/json');
+        });
     }
 }

+ 61 - 0
sistema-mantenimiento-back/app/Http/Controllers/EncryptionController.php

@@ -0,0 +1,61 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use Illuminate\Http\Request;
+
+class EncryptionController extends Controller{
+    private $public_key = "WrBEGoJnMnMhC/2hiaYypcmPwP9Z4p4/bNex0T/WUWA=";
+    private $secret_key = "CEIBkv7QG1WoAoBO7Ny5cqzyJ5yCUwBMhnFYUBbCeTk=";
+
+    public function encrypt($msg){
+        $nonce = random_bytes(SODIUM_CRYPTO_BOX_NONCEBYTES);
+        $nonceArr = array();
+        for($i = 0; $i < strlen($nonce); $i++){
+            $char = $nonce[$i];
+            $ascii = ord($char);
+            $nonceArr[] = $ascii;
+        }
+        $nonceJson = json_encode($nonceArr);
+        $nonceStr = base64_encode($nonceJson);
+
+        $encryption_key = sodium_crypto_box_keypair_from_secretkey_and_publickey(
+            base64_decode($this->secret_key), 
+            base64_decode($this->public_key));
+        $encrypted = sodium_crypto_box($msg, $nonce, $encryption_key);
+        $encryptedArr = array();
+        for($i = 0; $i < strlen($encrypted); $i++){
+            $char = $encrypted[$i];
+            $ascii = ord($char);
+            $encryptedArr[] = $ascii;
+        }
+        $encryptedJson = json_encode($encryptedArr);
+        $encryptedStr = base64_encode($encryptedJson);
+
+        return base64_encode($encryptedStr . "|" . $nonceStr);
+    }
+
+    public function decrypt($enc){
+        $dec = base64_decode($enc);
+        $decArr = explode("|", $dec);
+        $nonceDec = base64_decode($decArr[1]);
+        $caddec = base64_decode($decArr[0]);
+        $nonceArr = json_decode($nonceDec);
+        $cadArr = json_decode($caddec);
+
+        $nonceF = "";
+        foreach($nonceArr as $asciiF){
+            $nonceF .= chr($asciiF);
+        }
+
+        $cadF = "";
+        foreach($cadArr as $asciiF){
+            $cadF .= chr($asciiF);
+        }
+
+        $encryption_key_dec = sodium_crypto_box_keypair_from_secretkey_and_publickey(base64_decode($secret_key), base64_decode($public_key));
+        $decrypted = sodium_crypto_box_open($cadF, $nonceF, $encryption_key_dec);
+
+        return $decrypted;
+    }
+}

+ 75 - 0
sistema-mantenimiento-back/app/Http/Controllers/LoginController.php

@@ -0,0 +1,75 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Validator;
+use Illuminate\Support\Facades\DB;
+use Illuminate\Support\Facades\Hash;
+use Illuminate\Support\Carbon;
+
+use Firebase\JWT\JWT;
+use Firebase\JWT\Key;
+
+class LoginController extends Controller{
+    private $responseController;
+    private $encryptionController;
+    private $secretKey = "ydl27x22cNsNY0z6o3Fr6XZoUvsX0QMZx6MaiwN+KCnM6APS4Xbb7GDfudOYD5uD/r8TzQElh4d4HIal5Os0XA==";
+
+    public function __construct(
+        $responseController = new ResponseController(),
+        $encryptionController = new EncryptionController(),
+    ){
+        $this->responseController = $responseController;
+        $this->encryptionController = $encryptionController;
+    }
+    public function login(Request $request){
+        $validator = Validator::make($request->all(), [
+            'email' => 'required|string|email',
+            'password' => 'required|string'
+        ]);
+        
+        if($validator->fails()){
+            return $this->responseController->makeResponse(
+                true,
+                "Se encontraron uno o más errores.",
+                $this->responseController->makeErrors(
+                    $validator->errors()->messages()
+                ),
+                401
+            );
+        }
+        
+        $login = $request->all();
+        $usr = DB::table('samusua')->where('USUA_EMAI', '=', $login['email'])->first();
+        
+        if(is_null($usr)){
+            return $this->responseController->makeResponse(true, "El correo electrónico no está registrado.", [], 404);
+        }
+
+        $contra = $usr->USUA_CONT;
+        if(!Hash::check($login['password'], $contra)){
+            return $this->responseController->makeResponse(true, "La contraseña es incorrecta.", [], 401);
+        }
+
+        $now = Carbon::now('America/Mexico_city');
+        $iat = $now->timestamp;
+        $cad = $now->addDay()->timestamp;
+
+        $payload = [
+            "iss" => $login['email'],
+            "aud" => "dominio.syp.mx",
+            "iat" => $iat,
+            "cad" => $cad 
+        ];
+
+        $token = JWT::encode($payload, $this->secretKey, 'EdDSA');
+
+        return $this->responseController->makeResponse(false, "EXITO.", [
+            "IDUSUARIO" => $this->encryptionController->encrypt($usr->USUA_IDUS),
+            "NOMREUSUARIO" => $this->encryptionController->encrypt($usr->USUA_NOMB),
+            "CORREO" => $this->encryptionController->encrypt($usr->USUA_EMAI),
+            "TOKEN" => $token,
+        ]);
+    }
+}

+ 34 - 0
sistema-mantenimiento-back/app/Http/Controllers/ResponseController.php

@@ -0,0 +1,34 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use Illuminate\Http\Request;
+
+class ResponseController extends Controller{
+    public function makeResponse($error, $msg, $response = [], $code = 200){
+        $respuesta = json_encode([
+            "error" => $error,
+            "msg" => $msg,
+            "response" => $response
+        ]);
+
+        return response($respuesta, $code)->header('Content-Type', 'application/json');
+    }
+
+    public function makeErrors($erroresObj){
+        $erroresArr = array();
+
+        foreach($erroresObj as $key => $value){
+            foreach($value as $key0 => $value0){
+                if(array_key_exists($key, $erroresArr)){
+                    $val = $erroresArr[$key] . "|" . $value0;
+                    $erroresArr[$key] = $val;
+                }else{
+                    $erroresArr[$key] = $value0;
+                }
+            }
+        }
+
+        return $erroresArr;
+    }
+}

+ 1 - 0
sistema-mantenimiento-back/app/Http/Kernel.php

@@ -63,5 +63,6 @@ class Kernel extends HttpKernel
         'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
         'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
         'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
+        'jwt.auth' => \App\Http\Middleware\JWTMiddleware::class,
     ];
 }

+ 60 - 0
sistema-mantenimiento-back/app/Http/Middleware/JWTMiddleware.php

@@ -0,0 +1,60 @@
+<?php
+
+namespace App\Http\Middleware;
+
+use Closure;
+use Illuminate\Http\Request;
+use Illuminate\Support\Carbon;
+use Illuminate\Support\Facades\DB;
+
+use Firebase\JWT\JWT;
+use Firebase\JWT\Key;
+
+use App\Http\Controllers\ResponseController;
+
+class JWTMiddleware{
+    private $responseController;
+    private $publicKey = "zOgD0uF22+xg37nTmA+bg/6/E80BJYeHeByGpeTrNFw=";
+    /**
+     * Handle an incoming request.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @param  \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse)  $next
+     * @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
+     */
+    public function __construct($responseController = new ResponseController()){
+        $this->responseController = $responseController;
+    }
+
+    public function handle(Request $request, Closure $next){
+        $auth = $request->header('Authorization');
+        if(is_null($auth)){
+            return $this->responseController->makeResponse(true, "No se encontró el token de autorización.", [], 401);
+        }else if(!str_contains($auth, "Bearer")){
+            return $this->responseController->makeResponse(true, "No se encontró el token de autorización.", [], 401);
+        }
+
+        $token = str_replace("Bearer ", "", $auth);
+        if(strlen($token) < 234){
+            return $this->responseController->makeResponse(true, "Token inválido.", [], 401);
+        }
+
+        $decoded = JWT::decode($token, new Key($this->publicKey, 'EdDSA'));
+        $now = Carbon::now('America/Mexico_city')->timestamp;
+
+        $usr = DB::table('samusua')->where('USUA_EMAI', '=', $decoded->iss)->first();
+        if(is_null($usr)){
+            return $this->responseController->makeResponse(true, "El usuario que generó el token no está registrado en la base.", [], 401);
+        }
+
+        if($decoded->aud != "dominio.syp.mx"){
+            return $this->responseController->makeResponse(true, "El token no fue generado en este sistema.", [], 401);
+        }
+
+        if($now > $decoded->cad){
+            return $this->responseController->makeResponse(true, "Token expirado.", [], 401);
+        }
+        
+        return $next($request);
+    }
+}

+ 1 - 0
sistema-mantenimiento-back/composer.json

@@ -6,6 +6,7 @@
     "license": "MIT",
     "require": {
         "php": "^8.0.2",
+        "firebase/php-jwt": "^6.0",
         "guzzlehttp/guzzle": "^7.2",
         "laravel/framework": "^9.2",
         "laravel/sanctum": "^2.14.1",

+ 58 - 1
sistema-mantenimiento-back/composer.lock

@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "12524947d8c752f84bc21aaaede06bfa",
+    "content-hash": "752c90f03ae46b1f7274a01f90165f75",
     "packages": [
         {
             "name": "brick/math",
@@ -437,6 +437,63 @@
             ],
             "time": "2021-10-11T09:18:27+00:00"
         },
+        {
+            "name": "firebase/php-jwt",
+            "version": "v6.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/firebase/php-jwt.git",
+                "reference": "0541cba75ab108ef901985e68055a92646c73534"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/firebase/php-jwt/zipball/0541cba75ab108ef901985e68055a92646c73534",
+                "reference": "0541cba75ab108ef901985e68055a92646c73534",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": ">=4.8 <=9"
+            },
+            "suggest": {
+                "paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Firebase\\JWT\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Neuman Vong",
+                    "email": "neuman+pear@twilio.com",
+                    "role": "Developer"
+                },
+                {
+                    "name": "Anant Narayanan",
+                    "email": "anant@php.net",
+                    "role": "Developer"
+                }
+            ],
+            "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.",
+            "homepage": "https://github.com/firebase/php-jwt",
+            "keywords": [
+                "jwt",
+                "php"
+            ],
+            "support": {
+                "issues": "https://github.com/firebase/php-jwt/issues",
+                "source": "https://github.com/firebase/php-jwt/tree/v6.0.0"
+            },
+            "time": "2022-01-24T15:18:34+00:00"
+        },
         {
             "name": "fruitcake/php-cors",
             "version": "v1.2.0",

+ 6 - 0
sistema-mantenimiento-back/routes/api.php

@@ -17,3 +17,9 @@ use Illuminate\Support\Facades\Route;
 Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
     return $request->user();
 });
+
+Route::post("/login", "App\Http\Controllers\LoginController@login");
+
+Route::middleware(['jwt.auth'])->group(function(){
+    
+});