style attribute javascript authentication react-native redux

javascript - attribute - meta html



Reaccionar la autenticación básica Native+Redux (3)

Cuando una aplicación se comunica con una API HTTP que impone alguna forma de autenticación, la aplicación generalmente sigue estos pasos:

  1. La aplicación no está autenticada, por lo que solicitamos al usuario que inicie sesión.
  2. El usuario ingresa sus credenciales (nombre de usuario y contraseña) y toca Enviar.
  3. Enviamos estas credenciales a la API e inspeccionamos la respuesta:
    • En caso de éxito (200 - OK): almacenamos en caché el token / hash de autenticación, porque vamos a usar este token / hash en cada solicitud posterior .
      • Si el token / hash no funciona durante cualquiera de las siguientes solicitudes de la API (401 - No autorizado), necesitaremos invalidar el hash / token y solicitar al usuario que vuelva a iniciar sesión.
    • O bien, en caso de error (401 - No autorizado): mostramos un mensaje de error al usuario, pidiéndole que vuelva a ingresar sus credenciales.

Iniciar sesión

En función del flujo de trabajo definido anteriormente, nuestra aplicación comienza mostrando un formulario de inicio de sesión, el paso 2 se inicia cuando el usuario toca el botón de inicio de sesión que despacha el creador de acciones de login continuación:

/// actions/user.js export function login(username, password) { return (dispatch) => { // We use this to update the store state of `isLoggingIn` // which can be used to display an activity indicator on the login // view. dispatch(loginRequest()) // Note: This base64 encode method only works in NodeJS, so use an // implementation that works for your platform: // `base64-js` for React Native, // `btoa()` for browsers, etc... const hash = new Buffer(`${username}:${password}`).toString(''base64'') return fetch(''https://httpbin.org/basic-auth/admin/secret'', { headers: { ''Authorization'': `Basic ${hash}` } }) .then(response => response.json().then(json => ({ json, response }))) .then(({json, response}) => { if (response.ok === false) { return Promise.reject(json) } return json }) .then( data => { // data = { authenticated: true, user: ''admin'' } // We pass the `authentication hash` down to the reducer so that it // can be used in subsequent API requests. dispatch(loginSuccess(hash, data.user)) }, (data) => dispatch(loginFailure(data.error || ''Log in failed'')) ) } }

Hay un montón de código en la función anterior, pero consoléntese con el hecho de que la mayoría del código está desinfectando la respuesta y puede abstraerse.

Lo primero que hacemos es enviar una acción LOGIN_REQUEST que actualiza nuestra tienda y nos permite saber que el usuario está isLoggingIn .

dispatch(loginRequest())

Usamos esto para mostrar un indicador de actividad ( rueda giratoria, "Cargando ...", etc. ) y para deshabilitar el botón de inicio de sesión en nuestra vista de registro.

A continuación, base64 codifica el nombre de usuario y la contraseña del usuario para la autenticación básica http y lo pasa a los encabezados de la solicitud.

const hash = new Buffer(`${username}:${password}`).toString(''base64'') return fetch(''https://httpbin.org/basic-auth/admin/secret'', { headers: { ''Authorization'': `Basic ${hash}` } /* ... */

Si todo fue bien, despacharemos una acción LOGIN_SUCCESS , lo que nos lleva a tener un hash autenticación en nuestra tienda, que usaremos en las solicitudes posteriores.

dispatch(loginSuccess(hash, data.user))

Por otro lado, si algo salió mal, también queremos que el usuario sepa:

dispatch(loginFailure(data.error || ''Log in failed'')

Los creadores de la acción loginSuccess , loginFailure y loginRequest son bastante genéricos y no garantizan muestras de código. Ver: https://github.com/peterp/redux-http-basic-auth-example/blob/master/actions/user.js)

Reductor

Nuestro reductor también es típico:

/// reducers/user.js function user(state = { isLoggingIn: false, isAuthenticated: false }, action) { switch(action.type) { case LOGIN_REQUEST: return { isLoggingIn: true, // Show a loading indicator. isAuthenticated: false } case LOGIN_FAILURE: return { isLoggingIn: false, isAuthenticated: false, error: action.error } case LOGIN_SUCCESS: return { isLoggingIn: false, isAuthenticated: true, // Dismiss the login view. hash: action.hash, // Used in subsequent API requests. user: action.user } default: return state } }

Solicitudes de API posteriores

Ahora que tenemos un hash de autenticación en nuestra tienda, podemos pasarlo a los encabezados de las solicitudes posteriores.

En nuestro ejemplo a continuación, buscamos una lista de amigos para nuestro usuario autenticado:

/// actions/friends.js export function fetchFriends() { return (dispatch, getState) => { dispatch(friendsRequest()) // Notice how we grab the hash from the store: const hash = getState().user.hash return fetch(`https://httpbin.org/get/friends/`, { headers: { ''Authorization'': `Basic ${hash}` } }) .then(response => response.json().then(json => ({ json, response }))) .then(({json, response}) => { if (response.ok === false) { return Promise.reject({response, json}) } return json }) .then( data => { // data = { friends: [ {}, {}, ... ] } dispatch(friendsSuccess(data.friends)) }, ({response, data}) => { dispatch(friendsFailure(data.error)) // did our request fail because our auth credentials aren''t working? if (response.status == 401) { dispatch(loginFailure(data.error)) } } ) } }

Puede encontrar que la mayoría de las solicitudes API normalmente envían las mismas 3 acciones que anteriormente: API_REQUEST , API_SUCCESS y API_FAILURE , y como tal, la mayoría del código de solicitud / respuesta se puede insertar en el middleware de Redux.

Buscamos el token de autenticación hash de la tienda y configuramos la solicitud.

const hash = getState().user.hash return fetch(`https://httpbin.org/get/friends/`, { headers: { ''Authorization'': `Basic ${hash}` } }) /* ... */

Si la respuesta de la API con un código de estado 401, entonces tenemos que eliminar nuestro hash de la tienda, y presentar al usuario con un registro en la vista de nuevo.

if (response.status == 401) { dispatch(loginFailure(data.error)) }

He respondido la pregunta genéricamente y solo trato con http-basic-auth.

Creo que el concepto puede seguir siendo el mismo, presionarás accessToken y refreshToken en la tienda y lo extraerás en las solicitudes posteriores.

Si la solicitud falla, tendrá que enviar otra acción que actualice el accessToken y luego recupere la solicitud original.

Estoy buscando una forma de crear una autenticación básica para mi aplicación nativa de Reaction. No pude encontrar ningún buen ejemplo para la aplicación de react-native.

  • Para iniciar sesión, la aplicación envía el correo electrónico / contraseña + clientSecret a mi servidor
  • Si está bien, el servidor devuelve accessToken + refreshToken
  • El usuario ha iniciado sesión, todas las demás solicitudes incluyen el portador con el accessToken.
  • Si el accessToken caduca, la aplicación solicita una nueva con el refreshToken automáticamente.
  • El usuario permanece conectado todo el tiempo, los estados deben guardarse en el teléfono.

¿Cuál sería el mejor enfoque para esto?

Gracias.



No he visto demasiado a través de ejemplos en esta área, y creo que definitivamente es algo que necesita más cobertura. Todavía no he implementado la autenticación yo mismo, de lo contrario, le indicaré algunos ejemplos de código. Pero puedo señalarle un par de enlaces que he recopilado que pueden ayudarlo en la dirección correcta ...

Independientemente de cómo realice su autenticación, deberá almacenar de forma segura sus tokens de acceso, actualización y secreto. En iOS creo que harías eso usando keychain y para Android parece que KeyStore es el camino. Puede encontrar oblador/react-native-keychain útil, aunque todavía no es compatible con Android parece que puede ser compatible con Android pronto .