Redux:登录请求后保存cookie的正确位置是什么?

Ste*_*eve 20 cookies redux

我有以下情况:用户输入他的凭据并单击" 登录"按钮.API调用在动作创建者中完成redux-thunk.API调用成功后,将调度另一个包含服务器响应的操作.在(成功)登录后,我想将用户会话ID存储在cookie中(通过react-cookie).

行动创造者

export function initiateLoginRequest(username, password) {
  return function(dispatch) {
    dispatch(loginRequestStarting())

    return fetch('http://path.to/api/v1/login',
      {
        method: 'POST',
        headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          username: username,
          password: password
        })
      })
      .then(checkStatus)
      .then(parseJSON)
      .then(function(data) {
        dispatch(loginRequestSuccess(data))
      })
      .catch(function(error) {
        dispatch(loginRequestError(error))
      })
  }
}

export function loginRequestSuccess(user) {
  return {
    type: ActionTypes.LOGIN_REQUEST_SUCCESS,
    user
  }
}
Run Code Online (Sandbox Code Playgroud)

减速器

export default function user(state = initialState, action) {
  switch (action.type) {
    case ActionTypes.LOGIN_REQUEST_SUCCESS:
      cookie.save('sessionId', action.user.sid, { path: '/' })
      return merge({}, state, {
        sessionId: action.user.sid,
        id: action.user.id,
        firstName: action.user.first_name,
        lastName: action.user.last_name,
        isAuthenticated: true
      })
    default:
      return state
  }
}
Run Code Online (Sandbox Code Playgroud)

现在,负责LOGIN_REQUEST_SUCCESS的reducer保存了cookie.我知道减速器必须是纯函数.

是否在减速器中保存了一个违反此原则的cookie?将cookie保存在动作创建者中会更好吗?

Mar*_*cke 9

看看redux-persist.

您可以保留/保存您的减速器(或其中的一部分)LocalStorage.

概念

  • 启动登录.
  • 从服务器接收cookie.
  • 调度登录成功.
  • Reducer将cookie存储在内存中.
  • 持久中间件在LocalStorage中存储reducer状态.

安装

npm install --save-dev redux-persist
Run Code Online (Sandbox Code Playgroud)

示例用法

创建一个包装持久性/补充逻辑的组件.

AppProvider.js

import React, { Component, PropTypes } from 'react';
import { Provider } from 'react-redux';
import { persistStore } from 'redux-persist';

class AppProvider extends Component {
    static propTypes = {
        store: PropTypes.object.isRequired,
        children: PropTypes.node
    }

    constructor(props) {
        super(props);

        this.state = { rehydrated: false };
    }

    componentWillMount() {
        const opts = {
            whitelist: ['user'] // <-- Your auth/user reducer storing the cookie
        };

        persistStore(this.props.store, opts, () => {
            this.setState({ rehydrated: true });
        });
    }

    render() {
        if (!this.state.rehydrated) {
            return null;
        }

        return (
            <Provider store={this.props.store}>
                {this.props.children}
            </Provider>
        );
    }
}

AppProvider.propTypes = {
    store: PropTypes.object.isRequired,
    children: PropTypes.node
}

export default AppProvider;
Run Code Online (Sandbox Code Playgroud)

然后,在您index.js设置的文件或文件中store,将渲染的组件包装在新的组件中AppProvider.

index.js

...
import AppProvider from 'containers/AppProvider.jsx';
...

render((
    <AppProvider store={store}>
        ...
    </AppProvider>
), document.getElementById('App'));
Run Code Online (Sandbox Code Playgroud)

这会将您的userreducer状态序列化为LocalStorage每次更新商店/状态.您可以打开开发工具(Chrome)并查看Resources=> Local Storage.

  • 在 localStorage 中存储令牌和其他安全信息并不安全:( (2认同)

Níc*_*sen 5

我不确定这是否是“正确”的方法,但是这就是我的团队将登录的用户保留在我们构建的Redux应用程序中的方式:

我们有一个非常默认的架构,一个API可以在一侧接收请求,而React / Redux / Single Page应用则在另一侧使用此API端点。

当用户凭据有效时,负责登录的API端点将使用用户对象(包括访问令牌)对应用程序做出响应。该应用程序在每个请求中都会使用访问令牌,以根据API验证用户。

当应用程序从API接收到此用户信息时,会发生两件事:1)将一个操作分派给用户reducer,例如ADD_USER,将该用户包括在用户存储中; 2)用户的访问令牌保留在中localStorage

之后,任何组件都可以连接到用户减速器并使用持久访问令牌来知道谁是登录用户,当然,如果您没有访问令牌,localStorage则意味着该用户尚未登录。

在组件层次结构的顶部,我们有一个组件负责连接到用户reducer,根据持久化访问令牌的方式获取当前用户localStorage,并在React的上下文中传递该当前用户。因此,我们避免依赖于当前用户的每个组件都必须连接到用户reducer并从中读取信息localStorage,我们假设这些组件将始终从应用程序上下文中接收当前用户。

存在一些挑战,例如令牌过期,这增加了解决方案的复杂性,但是基本上这就是我们的工作方式,并且运行良好。


Chr*_*ies 4

我可能会亲自在服务器端设置 cookie,并使其对 JavaScript 透明。但如果你真的想在客户端执行此操作,我会在操作助手中执行此操作。像这样的东西:

// Using redux-thunk
function login(user, password) {
  return dispatch => api.auth.login(user, password)
    .then(result => setCookie())
    .then(() => dispatch({type: 'USER_LOGGED_IN'}))
}
Run Code Online (Sandbox Code Playgroud)

或类似的东西。

动作助手不需要是纯粹的,但减速器应该是。因此,如果我正在做副作用,我会将它们放入行动助手中。