首页 文章

React Native Redux基本身份验证

提问于
浏览
24

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

  • 要登录,应用程序会将电子邮件/密码clientSecret发送到我的服务器

  • 如果正常,则服务器返回accessToken refreshToken

  • 用户已登录,所有其他请求包括具有accessToken的承载 .

  • 如果accessToken过期,应用程序会自动请求一个带有refreshToken的新服务器 .

  • 用户始终保持登录状态,状态应保存在手机中 .

对此最好的方法是什么?

谢谢 .

3 回答

  • 0

    我实际上正在制作一个视频教程系列,至少可以回答你提出的一些问题 . 该视频以及成绩单和示例代码可在此处找到:http://codecookbook.co/post/how-to-build-a-react-native-login-form-with-redux-pt1/

  • 4

    当应用程序与强制执行某种形式身份验证的HTTP API进行通信时,应用程序通常会遵循以下步骤:

    • 该应用未经过身份验证,因此我们提示用户登录 .

    • 用户输入凭据(用户名和密码),然后点击提交 .

    • 我们将这些凭证发送给API,并检查响应:

    • 成功(200 - OK):我们缓存身份验证令牌/哈希,因为我们将在每个后续请求中使用此令牌/哈希 .

    • 如果令牌/哈希在任何后续API请求(401 - 未授权)期间不起作用,我们将需要使哈希/令牌无效并提示用户再次登录 .

    • 或者,失败时(401 - 未经授权):我们向用户显示错误消息,提示他们重新输入凭据 .

    登录

    根据上面定义的工作流程,我们的应用程序首先显示一个登录表单,当用户点击下面调度 login 动作创建者的登录按钮时,第2步启动:

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

    上面的函数中有很多代码,但是大多数代码正在清理响应并且可以将其抽象出来,这样做很舒服 .

    我们要做的第一件事就是发送一个动作 LOGIN_REQUEST 来更新我们的商店并让我们知道用户 isLoggingIn .

    dispatch(loginRequest())
    

    我们使用它来显示活动指示器(旋转轮,"Loading..."等),并在我们的登录视图中禁用登录按钮 .

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

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

    loginSuccessloginFailureloginRequest 动作创建者相当通用,并不真正保证代码示例 . 见: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
      }
    }
    

    后续API请求

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

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

    /// 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_REQUEST ,_01021889_和 API_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-basic-auth .

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

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

  • 57

    我在这个领域没有看到过多的例子,并且认为它肯定需要更多的报道 . 我自己还没有实现auth,否则我会指出一些代码示例 . 但我可以向您指出我收集的一些链接,可以帮助您朝着正确的方向......

    无论你如何执行你的身份验证,你'll need to securely store your access, refresh, and secret tokens. On iOS I believe you' d使用keychain做到这一点,对于Android,它看起来像KeyStore . 你可能会发现oblador/react-native-keychain很有帮助,虽然它还不支持android它looks like it may support android soon .

相关问题