我正在寻找一种为我的react-native 应用程序创建基本身份验证的方法.

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

最好的方法是什么?

谢谢

推荐答案

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

  1. 该应用程序未经身份验证,因此我们会提示用户登录.
  2. 用户输入他们的凭据(用户名和密码),然后点击提交.
  3. We send these credentials to the API, and inspect the response:
    • 成功时(200-OK):我们缓存身份验证令牌/哈希,因为我们将使用这个令牌/哈希in every subsequent请求.
    • 或者,失败时(401-未经授权):我们向用户显示一条错误消息,提示他们重新输入凭据.

Logging In

根据上面定义的工作流程,我们的应用程序首先显示一个登录表单,当用户点击登录按钮时,step 2将启动,该按钮将发送下面的login action creator:

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

上面的函数中有很多代码,但请放心

我们要做的第一件事是发送一个action LOGIN_REQUEST,它更新我们的store ,并让我们知道用户isLoggingIn.

dispatch(loginRequest())

我们使用它来显示活动指示器(spinning wheel, "Loading...", etc.),并在登录视图中禁用登录按钮.

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

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

如果一切顺利,我们将发送一个LOGIN_SUCCESS操作,这将导致我们的存储中有一个身份验证hash,我们将在后续请求中使用它.

dispatch(loginSuccess(hash, data.user))

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

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

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)

减速器

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

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

Subsequent API requests

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

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

/// 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中间件中.

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

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

如果API响应带有401状态代码,那么我们必须从存储中删除哈希,并再次向用户提供登录视图.

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

我已经笼统地回答了这个问题,并且只涉及http基本身份验证.

我认为这个概念可能会保持不变,你会在store 里推送accessTokenrefreshToken,然后在后续请求中提取.

如果请求失败,那么您将不得不发送另一个更新accessToken的操作,然后调用原始请求.

React-native相关问答推荐

没有给出相同价值观的时刻

使用FETCH发送BLOB/文件时为空

React Native 中的视图与 Flex 不占用相同的高度空间

为什么当键盘出现在react native 时我的按钮会上升?按钮视图位置是绝对的?

React Native Navigation const { navigate } = this.props.navigation;

为什么会出现此错误:Invariant Violation: Cannot update during an existing state transition

如何实时从 react-native-camera 获取帧

如何在 React-Native Android 中检测拖动事件的结束

如何在 React Native For Android 中删除启动画面后的白屏

React-Native + crypto:如何在 React-Native 中生成 HMAC?

React Native localhost 另一个调试器已经连接

有没有办法改变 IOS 标题上react-navigation 的默认后退按钮 colored颜色 ?

React Native STUCK 启动打包器

是否可以将 Image.getSize 与静态图像文件一起使用?

加载远程图像失败后加载本map像

Port 8081 already in use, packager is either not running or not running correctly Command /bin/sh failed with exit code 2

KeyboardAvoidingView - 隐藏键盘时重置高度

Tools > Android 菜单在 Android Studio 中不存在

未找到 React/RCTBridgeDelegate.h' 文件

为什么 this.state 在react-native中未定义?