【问题标题】:Store Credentials in Redux store is a good practice?在 Redux 商店中存储凭据是一个好习惯吗?
【发布时间】:2016-05-23 18:42:22
【问题描述】:

我正在尝试开发一个用于学习目的的 React/Redux 应用程序,我想知道到目前为止我所做的是否是一种好的做法或不推荐。 我必须处理的第一件事是处理授权请求。 我有一个 restfull api Rails 后端。该服务器响应附加在 headers 参数中的登录请求,例如 access-token。 此访问令牌仅对下一个请求有效,然后返回一个对下一个有效的新令牌,依此类推。

我以这种方式实现了这个流程: 商店分派执行传递用户名和密码的登录请求的操作。然后,当响应准备好时,我将凭据存储在 redux 存储中。 当我需要执行授权请求时,我在标头请求中设置这些参数。 当我收到响应时,我会使用从响应中获得的新凭据更新商店中的凭据。

为了更清楚,这里是我的代码:

import { combineReducers } from 'redux'
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';

const initialState = {
  currentUser: {
    credentials: {},
    user: {}
  },
  test: {},
  users: []
}

export const SUBMIT_LOGIN = 'SUBMIT_LOGIN'
export const SET_USER = 'SET_USER'
export const TEST = 'TEST'
export const SET_USERS = 'SET_USERS'
export const SET_CREDENTIALS = 'SET_CREDENTIALS'

//actions
const submitLogin = () => (dispatch) => {
  return postLoginRequest()
    .then(response => {
      dispatch(setCredentials(
        response.headers.get('access-token'),
        response.headers.get('client'),
        response.headers.get('expiry'),
        response.headers.get('token-type'),
        response.headers.get('uid')
      ));
      return response
    })
    .then(response => {
      return response.json();
    })
    .then(
      (user) => dispatch(setUser(user.data)),
    );
}

const performRequest = (api) => (dispatch) => {
  return api()
    .then(response => {
      dispatch(setCredentials(
        response.headers.get('access-token'),
        response.headers.get('client'),
        response.headers.get('expiry'),
        response.headers.get('token-type'),
        response.headers.get('uid')
      ));
      return response
    })
    .then(response => {return response.json()})
    .then(json => {console.log(json)})
}

const setUsers = (users) => {
  return {
    type: SET_USERS,
    users
  }
}

const setUser = (user) => {
  return {
    type: SET_USER,
    user
  }
}

const setCredentials = (
  access_token,
  client,
  expiry,
  token_type,
  uid
) => {
  return {
    type: SET_CREDENTIALS,
    credentials: {
      'access-token': access_token,
      client,
      expiry,
      'token-type': token_type,
      uid
    }
  }
}

const currentUserInitialState = {
  credentials: {},
  user: {}
}

const currentUser = (state = currentUserInitialState, action) => {
  switch (action.type) {
    case SET_USER:
      return Object.assign({}, state, {user: action.user})
    case SET_CREDENTIALS:
      return Object.assign({}, state, {credentials: action.credentials})
    default:
      return state
  }
}

const rootReducer = combineReducers({
  currentUser,
  test
})

const getAuthorizedHeader = (store) => {
  const credentials = store.getState().currentUser.credentials
  const headers = new Headers(credentials)
  return headers
}

//store creation

const createStoreWithMiddleware = applyMiddleware(
  thunk
)(createStore);

const store = createStoreWithMiddleware(rootReducer);

const postLoginRequest = () => {
  return fetch('http://localhost:3000/auth/sign_in', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      email: 'test@test.com',
      password: 'password',
    })
  })
}

const getUsers = () => {
  const autorizedHeader = getAuthorizedHeader(store)
  debugger
  return fetch('http://localhost:3000/users',
    {
      method: 'GET',
      headers : autorizedHeader
    }
  )
}


store.dispatch(submitLogin())

setTimeout(() => {
  console.log(store.dispatch(performRequest(getUsers)))
}, 2000)

我想知道在商店中存储敏感数据是否是一种好的做法,如果不是,我愿意接受任何建议以更好地开发此工作流程。

我的服务器上也有这个参数

config.batch_request_buffer_throttle = 5.seconds

有时需要同时向 API 发出多个请求。在这种情况下,批处理中的每个请求都需要共享相同的身份验证令牌。此设置确定在仍使用相同身份验证令牌的情况下请求可以相距多远。

这样,如果令牌仍然有效,我无法在 performRequest 函数中调度 setCredentials 操作,但我真的不知道如何检查它。

谢谢

【问题讨论】:

  • Redux 存储在内存中(除非您将其存储在其他地方)。如果是这种情况,一旦您重新加载页面,凭据和/或会话就会丢失。对我来说听起来很合理。
  • 对我来说听起来不太合理。对于移动或单页应用程序,用户“重新加载页面”可能需要数周时间,并且一直以来他的凭据都存储在内存中的某个位置。听起来像是一个可能的漏洞。
  • @VaclavSir 你的解决方案是什么?
  • 我同意@AndreyLuiz。将令牌/凭据放入 localStorage 并在需要发出服务器请求时检查 localStorage 的凭据。如果凭据不再存在或无效,请从存储中删除所有内容并执行 LOGOUT 操作。在您的 reducer 中,LOGOUT 操作应该返回一个空状态,因此有关上一个会话的所有信息也会从状态中删除。如果您真的想确保没有人使用过期凭据的应用程序,您还可以对 localStorage 中的凭据进行定期检查以确保它们有效
  • @JoeyGough 任何站点都可以访问您的本地存储,但本地存储是基于域的。因此,如果 www.abc.com 网站在您的本地存储中保存了任何内容,那么当您访问 www.def.com 时,它将无法访问 www.abc.com 保存的任何信息。

标签: reactjs authentication redux access-token


【解决方案1】:

没有。这不是一个好习惯。如果您希望更好地存储用户会话,请使用 cookie 会话来存储 JWT 以防 React.js。

如果 react-native 使用 react-native-keychain 来存储您的密码,我也建议使用 JWT 令牌或加密文本而不是纯文本。

您的实施主要取决于您的后端。如果您使用 passport.js 之类的库(对于 node.js 服务器),您可以使用 crypt 令牌来授权请求​​。但是,无论您必须通过何种方式进行身份验证,都不要将其直接存储在 state 中。

【讨论】:

  • 您能详细说明原因吗?您看到哪些缺点/安全问题?
【解决方案2】:

使用Modern Storage API 会对您有所帮助。

因为当您在 Redux Store 中获取您的 auth 数据时,如果页面被刷新或历史移动(返回 || go),则 Store Values 不再存在。并且您的应用将在刷新后请求身份验证数据 .. 刷新 ..

...

使用window.sessionStorage 可以在刷新或历史移动后保留数据。


  [AFTER LOGIN EVENT]

    window.sessionStorage.setItem(key,vlaue)

  [AFTER LOGOUT EVENT]

    window.sessionStorage.clear() <- removes all records in sessionStorage.
    window.sessionStorage.removeItem(key) 

【讨论】:

  • 我不推荐这种存储凭据的方法。这是不安全的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-18
  • 2021-01-21
  • 2016-01-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多