una segura que por parte net example construyendo con basada autenticacion acceso php jquery reactjs authorization lumen

php - segura - json web token java



Sesiones en autenticación basada en token (8)

Estoy creando una aplicación en PHP Lumen que devuelve un token al iniciar sesión. No estoy seguro de cómo proceder más allá de esto.

¿Cómo se supone que debo mantener una sesión usando estos tokens?

Específicamente, ¿cómo almaceno los tokens en el lado del cliente si estoy usando reactjs o vanilla HTML / CSS / jQuery y los envío en cada solicitud que hago para la parte segura de mi aplicación web?


Para el cifrado y descifrado que puede utilizar en el modelo de cripta de laravel construido

utilizar Illuminate / Support / Facades / Crypt;

Lo que hacemos para generar el token de las API es tomar una matriz de campos obligatorios.

Vamos a crear datos

$data = [ ''user_id'' => $user->id, ''time_stemp'' => /Carbon::now() // Carbon is laravel''s time model(class) for managing times ''expire_on'' => /Carbon::now()->addDays(2); //here i''m setting token expires time for 2 days you can change any ]; $data = serialize($data);

luego encripta tus datos con Crypt

$accessToken = Crypt::encrypt($data);

Ahora envíelo al front-end en respuesta y guárdelo en un almacenamiento local o en una cookie, cualquier cosa que no necesite tiempo aquí solo verificará el servidor.

Ahora, en cada solicitud, pase ese token y en el lado del servidor cree un software intermedio que analizará sus datos y, si el tiempo del token es menor, el tiempo de vencimiento luego avanza, de lo contrario, envíe el error 403 o lo que desee.

Cómo analizar datos en el lado del servidor

Cree middleware usando el comando: php artisan make: middleware ApiAuth luego es parte manejable

//Accesstoken you passed in $headers or in $request param use whatever you like $searilizerData = Crypt::decrypt($headers[''AccessToken'']); $data = unserialize($searilizerData); //check if expire_on is less then current server time if($data[''expire_on] <= /Curbon::now()){ next(); // let them contuine and access data } else { throw new Exception ("Your token has expired please regenerate your token",403); }

Espero que esto ayude :)


Actualmente trabajando en el mismo tipo de aplicación usando lumen para API. Siguiendo los 3 pasos para la autenticación basada en token en Lumen con JWT :

1. Crear un token y volver después de iniciar sesión correctamente

public function login(Request $request) { $token = $this->jwt->attempt([''user_name'' => $data[''user_name''], ''password'' => $data[''password'']]); //$token = $this->jwt->attempt($data); if (!$token) { $response = array(''success'' => false, ''data'' => null, ''detail'' => array(''message'' => Messages::MSG_INVALID_USER, ''error'' => array(Messages::MSG_INVALID_USER))); return response()->json($response); } else { $user = /Auth::setToken($token)->user(); $data = array(''token'' => $token,''user_id'' => $user->id); $response = array(''success'' => true, ''data'' => $data, ''detail'' => array(''message'' => Messages::MSG_SUCCESS, ''error'' => null)); return response()->json($response); } }

2. Definir middleware para la verificación de token.

public function handle($request, Closure $next, $guard = null) { try { $token = $request->header(''X-TOKEN''); $user_id = $request->header(''X-USER''); $user = /Auth::setToken($token)->user(); if ($user && $user->id == $user_id) { return $next($request); } else { $response = array(''success'' => false, ''data'' => null, ''detail'' => array(''message'' => Messages::MSG_ERR_INVALID_TOKEN, ''error'' => Messages::MSG_ERR_INVALID_TOKEN)); return response()->json($response); } } catch (Exception $ex) { $response = array(''success'' => false, ''data'' => null, ''detail'' => array(''message'' => Messages::MSG_ERROR_500, ''error'' => array($ex))); return response()->json($response); } }

3. Almacenar el token en localstorage o en cookies

localStorage.setItem("Token", JSON.stringify(TokenData)); TokenData = JSON.parse(localStorage.getItem("Token"));

o

$.cookie(''Token'', JSON.stringify(TokenData), {expires: 1, path: ''/''}); TokenData = JSON.parse($.cookie("Token"));

4. Enviar token con cada solicitud en los encabezados

Solicitud con encabezados personalizados

$.ajax({ url: ''foo/bar'', headers: { ''X-TOKEN'': TokenData.Token ,''X-USER'': TokenData.UserId} });

Encabezados a cada solicitud.

$.ajaxSetup({ headers: { ''X-TOKEN'': TokenData.Token ,''X-USER'': TokenData.UserId} });

Espero que te ayude.

Nota: agregue algunos controles y validaciones de datos mientras lee datos de localstorage o cookies .


Asumamos que quieres construir una aplicación con.

  1. Reaccionar
  2. API REST con PHP
  3. Usando JWT

1. Introducción

Debes olvidarte de las sesiones al construir API REST.

Las API REST están destinadas a ser sin estado, por lo que no deben depender de las sesiones, deben procesar las solicitudes solo con los datos proporcionados por el cliente.

2. Autenticación

Todo lo que el cliente quiere hacer es solo intercambiar un username y password para un token.

Este es un ejemplo de solicitud HTTP.

POST /api/v1/authentication HTTP/1.1 Host: localhost Content-Type: application/json { "username": "foo", "password": "bar" }

Y la respuesta es:

{ "token": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" }

3. vamos a entrar en más detalles en la solicitud / respuesta

¿Cómo nuestra API procesará la solicitud de autenticación?

  1. Verificará si un usuario con nombre de usuario foo & password bar está fundado y está activo en DB

  2. Se generará un JWT (Json Web Token)

  3. Se devolverá la respuesta que contiene el JWT.

Este es un método de autenticación super simple, solo por ejemplo.

public function authAction() { /** Get your payload somehow */ $request = $_POST; //Validate if username & password are given/ $user = $this->model->auth($username, $password); if(!$user) { //throw error for not valid credentials } $jwt = $this->jwt->create($user); //return response with $jwt }

Como veis no hay sesiones fijas ni nada.

¿Cómo nuestro lado cliente procesará la respuesta?

El cliente podría usar algún paquete como superagent para manejar las solicitudes y respuestas a nuestra API de esta manera el proceso se simplificará a esto:

let data = { username: email, password: password }; request .post(''/api/v1/authentication'') .set(''Content-Type'', ''application/json'') .send(data) .end(function (error, response) { //response.body.token });

4. Creando JWT en el lado del servidor

Podría usar algún paquete 3RD PT para generar y validar JWT en lugar de escribirlo usted mismo.

Mira este package , puedes ver cómo se hace.

Y recuerde siempre crear firmas fuertes. Recomiendo usar RSA keys

No estoy publicitando ni apoyando este proyecto, me ha resultado útil compartirlo aquí. Nunca lo había usado, estoy usando algo similar a esto en mis proyectos de NodeJS.

5. Guardar JWT en el lado del cliente

Son dos formas, como ya sabe, de localStorage y cookies Para mí estoy usando cookies, porque:

  1. Son un poco más secure .
  2. La fecha de caducidad se puede establecer sin implementar alguna lógica personalizada.
  3. Compatibilidad con navegadores más antiguos (navegadores muy antiguos, por lo que no es tan importante).

Pero todo depende de ti.

6. Usando JWT

A partir de ahora, cada solicitud al servidor debe incluir su JWT.

En su API REST debe escribir un método para validar el JWT e intercambiarlo por un objeto de usuario.

Ejemplo de solicitud:

let jwt = ...; //GET IT FROM LOCALSTORAGE OR COOKIE request .get(''/api/v1/posts'') .set(''Content-Type'', ''application/json'') .set(''Authorization'', jwt) .end(function (error, response) { });

Cómo API procesará esta solicitud

public function postsAction() { $jwt = $this->headers->get(''Authorization''); if(!$this->jwt->validate($jwt)) { //throw unauthorized error } $user = $this->model->exchangeJWT($jwt); //Your logic here }

7. Fecha de expiración y cookie.

Si está utilizando una cookie para guardar su JWT, tenga cuidado al establecer las fechas de caducidad.

La fecha de caducidad de la cookie debe ser igual a la fecha de caducidad de JWT.


Escribiré una lista rápida y las mejores prácticas, ya que hay muchas formas de hacerlo con código.

Backend

  • (POST) ruta de inicio de sesión {correo electrónico, contraseña} creará un token. Puede utilizar JWT (token web de Json). El token se devolverá al cliente. Dentro del token, puede almacenar algunos detalles básicos: ID de usuario, nombre de usuario, caducidad del token, tipo de usuario, etc. https://jwt.io/

Cliente

  • solicitud de ingreso, pase {email, contraseña}.

    Si tiene éxito, obtenga el token y guárdelo localmente, se prefiere el almacenamiento local, pero también es posible la cookie.

  • en cada carga de página con su aplicación de reacción, debe tener una función para verificar ese token, la descifrará y obtendrá los detalles para su uso posterior.

    Me refiero a obtener el nombre de usuario, ID de usuario, etc. Más importante si desea agregarlo, es la "caducidad", si el token caducó, redirige al usuario a la página de inicio de sesión, O puede volver a solicitar un token nuevo. Realmente depende de tu aplicación.

  • cerrar sesión, es bastante simple ... simplemente quite el token del lado del cliente y redirija a la página de inicio de sesión.

  • Asegúrese de que para las páginas "autenticadas", verifique que el token exista, y aún más puede verificar el tipo de usuario.

** para la decodificación del lado del cliente de JWT, puede utilizar: https://www.npmjs.com/package/jwt-client


Lo que normalmente hago es mantener el token en el almacenamiento local, de esta manera puedo conservar el token incluso si el usuario abandona el sitio.

localStorage.setItem(''app-token'', theTokenFromServer);

Cada vez que el usuario carga la página, lo primero que hago es buscar la existencia del token.

token = localStorage.getItem(''app-token'');

Si utilizo reaccionar, mantendría el token en el estado global (utilizando redux por ejemplo):

function loadAppToken(token) { return { type: ''LOAD_TOKEN'', payload: { token }, }; }

Con javascript de vainilla lo mantendría en mi utilidad de conexión. Que podría parecerse a lo siguiente:

const token = localStorage.getItem(''app-token''); export function request(config) { const { url, ...others } = config; return fetch(url, { ...others, credentials: ''include'', headers: { ''Authorization'': `Bearer ${token}` }, }); }

Todavía tendría una utilidad de recuperación en una aplicación de reacción, similar al código anterior, pero enviaría el token con las opciones, obteniéndolo en un middleware de redux para cada solicitud.


Puede almacenarlo en el almacenamiento local del navegador y luego configurarlo en el encabezado de cada solicitud al servidor.


Realmente no necesitas ningún ReactJS o VanillaJS. Solo HTML puro y PHP en realidad. Lo que hago es simplemente almacenarlo como una cookie.

En primer lugar, cuando reciba el token de Lumen, guárdelo en su base de datos de usuarios para usuarios específicos. A continuación, establezca la identificación de usuario y acceda a las cookies que caducan después de un cierto tiempo con este código:

setcookie(''userid'',$userid, time()+(3600 * 24 * 15),"/"); setcookie(''accesstoken'',$accesstoken, time()+(3600 * 24 * 15),"/"); header(''Location: /home.php''); //You can change the 15 in setcookie() to amount of days the cookie will expire in. //The "/" in setcookie is important, because it ensures the cookies will be available on every page the user visits on your website. //The header function redirects to your home page after log in

Entonces a continuación es cómo se vería tu página de inicio. Comprueba si existe una cookie accesstoken, si es así, verifica que el token coincida con el token actual en la base de datos del usuario. Si es una coincidencia, muestra la página ''conectado''. Si no, debe mostrar / redirigir a la página de inicio de sesión.

<?php if (isset($_COOKIE[''accesstoken''])) { //connect to your user database and check that the cookie accesstoken matches // if it doesn''t match, deal with it appropriately, such as deleting all cookies then redirecting to login page. } ?> <!DOCTYPE HTML> <html> <head> <title>Sup</title> </head> <body> <?php if (isset($_COOKIE[''accesstoken''])){ ?> <h1>User logged in!</h1> <h3>Do whatever you need to do if user is logged in</h3> <?php } else { ?> <h1>No accesstoken found</h1> <h3>More than likely you will want to show login page here</h3> <?php } ?> </body> </html>

y luego para cerrar la sesión es simple. El siguiente código elimina los accesstokens al establecerlos como caducados:

setcookie("accesstoken", "", time() - 3600); setcookie("userid", "", time() - 3600); header(''Location: /youareloggedout.html'');

Recuerde, esto es lo BÁSICO de un sistema funcional de inicio / cierre de sesión. Si explicara todas las medidas de seguridad necesarias, esta publicación sería aún más larga. Asegúrese de hacer su investigación. Algunos temas para comenzar son las declaraciones preparadas y la prevención de ataques XSS. :)


Recientemente he finalizado un portal web de reacción en el que hemos utilizado JWT para iniciar, mantener y caducar la sesión del usuario.

  1. Al iniciar sesión, enviar credenciales de usuario para iniciar sesión API. En caso de éxito, recupere el token de la API de back-end. El back-end mantiene la generación y expiración del token.
  2. Almacene el token en estado de reacción (usamos redux store) y en el almacenamiento de la sesión (en caso de que la página se actualice, podemos recuperarla del almacenamiento de la sesión).
  3. (Opcional) Inicie un contador por segundo en el almacenamiento de sesión (para verificar cuánto tiempo el usuario está inactivo)
  4. Después de iniciar sesión, cada llamada a la API requiere que el token se envíe en el encabezado. Las llamadas a la API se realizan utilizando fetch. Si la llamada a la API es exitosa, recuperamos el token del back-end y lo reemplazamos con el token existente (mantente actualizado).
  5. Todas las llamadas a la API se obtienen mediante una función genérica customFetch. La idea es tener una búsqueda genérica para ver si la respuesta de back-end es 401 (acceso denegado). Si es 401, el token está vencido o no es válido (el usuario está intentando acceder a algo sin iniciar sesión). En este caso, echamos al usuario fuera del portal, de vuelta a la página de inicio / inicio de sesión (mostrando el error de acceso denegado).
  6. (Opcional) Si el usuario está inactivo durante demasiado tiempo (al revisar el segundo contador> 900, es decir, 15 minutos), mostramos una advertencia al usuario de que la sesión está a punto de caducar, y le da la opción de continuar. Si los clics del usuario continúan, llamamos a una API para recuperar el perfil del usuario nuevamente, asegurándonos de que el token siga siendo válido. Si la API no tiene éxito, cerramos la sesión del usuario y la enviamos a la página de inicio / inicio de sesión. El segundo contador vuelve a 1 justo antes de que se realice cualquier llamada a la API (el usuario está activo y haciendo algo).
  7. No hace falta decir que antes de enviar al usuario a la página de inicio de sesión / inicio de sesión por cualquiera de los escenarios anteriores, borramos el almacenamiento de la sesión y restablecemos el estado (redux store).
  8. En caso de que se produzca una actualización, recuperamos el token del almacenamiento de la sesión y enviamos las acciones iniciales para volver a generar el estado (almacén de redux). Si cualquiera de las acciones (API) falla, mostramos el mensaje al usuario de que la sesión ha caducado o no es válida y usted debe iniciar sesión y, por lo tanto, enviar al usuario a la página de inicio / inicio de sesión.

Fragmentos de código

Supongamos que ha recuperado el token de la llamada a la API de inicio de sesión:

establecer el token en el almacenamiento y estado de la sesión (redux store)

window.sessionStorage.setItem(''partyToken'', token) store.dispatch({type: ''profile/setToken'', payload: { token }})

token de recuperación del almacenamiento o estado de la sesión (redux store)

const token = window.sessionStorage.getItem(''token'') const token = store.getState().profile && store.getState().profile.token

Por supuesto, puede definir una función común donde puede configurar / actualizar el token después de cada llamada a la API. Similar para la recuperación porque necesita el token antes de realizar una llamada a la API.