React Native + Redux基本认证 [英] React Native + Redux basic authentication

查看:89
本文介绍了React Native + Redux基本认证的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找一种为我的本机应用程序创建基本身份验证的方法. 我找不到任何本机应用程序的好例子.

I'm looking for a way to create a basic authentication for my react-native app. I couldn't find any good example for react-native app.

  • 要登录,该应用会将电子邮件/密码+ clientSecret发送到我的服务器
  • 如果确定,服务器将返回accessToken + refreshToken
  • 用户已登录,所有其他请求包括带有accessToken的承载.
  • 如果accessToken过期,则该应用会自动请求一个带有refreshToken的新令牌.
  • 用户始终保持登录状态,状态应保存在手机中.

什么是最好的方法?

谢谢.

推荐答案

当应用程序与实施某种形式的身份验证的HTTP API通信时,该应用程序通常遵循以下步骤:

When an app communicates with a HTTP API which enforces some form of authentication, the app typically follows these steps:

  1. 该应用未通过身份验证,因此我们提示用户登录.
  2. 用户输入其凭据(用户名和密码),然后点击提交.
  3. 我们将这些凭据发送到API,并检查响应:
    • 成功后(200-确定):我们缓存身份验证令牌/哈希,因为我们将在随后的每个请求中使用此令牌/哈希.
      • 如果令牌/哈希在随后的任何API请求(401-未经授权)中均不起作用,则需要使哈希/令牌无效,并提示用户再次登录.
  1. The app is not authenticated, so we prompt the user to log in.
  2. The user enters their credentials (username and password), and taps submit.
  3. We send these credentials to the API, and inspect the response:
    • On success (200 - OK): We cache the authentication token/ hash, because we're going to use this token/ hash in every subsequent request.
      • If the token/ hash does not work during any of the subsequent API requests (401 - Unauthorized), we'll need to invalidate the hash/ token and prompt the user to log in again.

登录

基于上面定义的工作流程,我们的应用程序首先显示一个登录表单,当用户点击登录按钮并分派login操作创建者时,第2步启动:

Logging In

Based on the work flow defined above our app starts by displaying a login form, step 2 kicks in when the user taps the login button which dispatches the login action creator below:

/// 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'))
    )
  }
}

上面的函数中有很多代码,但是请放心, 大部分代码都在清理响应,并且可以将其抽象化.

There's a lot of code in the function above, but take comfort in the fact that the majority of the code is sanitising the response and can be abstracted away.

我们要做的第一件事是调度操作LOGIN_REQUEST,该操作将更新我们的商店并让我们知道用户isLoggingIn.

The first thing we do is dispatch an action LOGIN_REQUEST which updates our store and lets us know that the user isLoggingIn.

dispatch(loginRequest())

我们用它来显示活动指示器(手纺车,正在加载..."等),并在登录视图中禁用登录按钮.

We use this to display an activity indicator (spinning wheel, "Loading...", etc.), and to disable the log in button in our log in view.

接下来,我们对base basic auth的用户名和密码进行base64编码,并将其传递给请求的标头.

Next we base64 encode the user's username and password for http basic auth, and pass it to the request's headers.

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

如果一切顺利,我们将分派一个LOGIN_SUCCESS操作,这将导致我们在商店中获得身份验证hash,我们将在后续请求中使用该身份验证.

If everything went well, we'll dispatch a LOGIN_SUCCESS action, which results in us having an authentication hash in our store, which we'll use in subsequent requests.

dispatch(loginSuccess(hash, data.user))

另一方面,如果出现问题,我们还想让用户知道:

On the flip side, if something went wrong then we also want to let the user know:

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

loginSuccessloginFailureloginRequest动作创建者是相当通用的,并不真正保证代码示例.参见: https://github .com/peterp/redux-http-basic-auth-example/blob/master/actions/user.js)

The loginSuccess, loginFailure, and loginRequest action creators are fairly generic and don't really warrant code samples. See: https://github.com/peterp/redux-http-basic-auth-example/blob/master/actions/user.js)

我们的减速器也是典型的:

Our reducer is also typical:

/// 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
  }
}

后续API请求

现在我们的商店中有一个身份验证哈希,我们可以将其传递到后续请求的标头中.

Subsequent API requests

Now that we have an authentication hash in our store we can pass it into subsequent request's headers.

在下面的示例中,我们为经过身份验证的用户获取朋友列表:

In our example below we're fetching a list of friends for our authenticated user:

/// 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))
        }
      }
    )
  }
}

您可能会发现,大多数API请求通常都会调度与上述相同的3个操作:API_REQUESTAPI_SUCCESSAPI_FAILURE,因此大多数请求/响应代码都可以推送到Redux中间件中.

You may find that most API requests typically dispatch the same 3 actions as above: API_REQUEST, API_SUCCESS, and API_FAILURE, and as such the majority of the request/ response code can be pushed into Redux middleware.

我们从商店中获取哈希身份验证令牌并设置请求.

We fetch the hash authentication token from the store and setup the request.

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

如果API响应带有401状态代码,则我们必须从商店中删除哈希,然后再次向用户显示登录视图.

If the API response with a 401 status code then we've got to remove our hash from the store, and present the user with a log in view again.

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


我已经一般性地回答了这个问题,并且只处理http-basic-auth.


I've answered the question generically and only dealing with http-basic-auth.

我认为概念可能保持不变,您将在商店中推送accessTokenrefreshToken,并在后续请求中将其提取.

I think that the concept may remain the same, you'll push the accessToken and refreshToken in the store, and extract it in subsequent requests.

如果请求失败,那么您将必须调度另一个操作,该操作将更新accessToken,然后重新调用原始请求.

If the request fails then you'll have to dispatch another action which updates the accessToken, and then recalls the original request.

这篇关于React Native + Redux基本认证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆