下一个 js redux-observable 使用 cookie 的持久身份验证令牌

next js redux-observable persistent auth token using cookie

我一直在尝试实现react server-side-rendering using next, and redux-observable,现在我想实现auth

登录时

关于访问需要授权的页面

上面的步骤发生在epics里面,如下

/epics/signin.js

export const signinEpic = (action$, store) => action$
  .ofType(SIGNIN)
  .mergeMap(() => {
    const params = { ... }
    return ajax(params)
      .concatMap((response) => {
        const { name, refreshToken } = response.body
        if (refreshToken && name === 'TokenExpiredError') {
          const refreshParams = { ... }
          return ajax(refreshParams)
            .concatMap((refreshResponse) => {
              setToken(refreshResponse.body.auth.token)
              const me = { ... }
              return [
                authSetMe(me),
                signinSuccess(),
              ]
            })
            .catch(error => of(signinFailure(error)))
        }
        const me = { ... }
        setToken(response.body.auth.token)
        return [
          authSetMe(me),
          signinSuccess(),
        ]
      })
      .catch(error => of(signinFailure(error)))
  })

我做了一些 console.log(Cookies.get('token')) 以确保 cookie 得到保存,并且它打印令牌很好,说它在那里,但是当我在浏览器控制台 > 应用程序 > Cookies 下检查时,什么也没有

因此在下面的 auth epic 中,getToken() 将始终 return '' 将始终调度 authMeFailure(error)

/epics/auth.js

// this epic will run on pages that requires auth by dispatching `authMe()`
export const authMeEpic = action$ => action$
  .ofType(AUTH_ME)
  .mergeMap(() => {
    const params = {
      ...,
      data: {
        ...
        Authorization: getToken() ? getToken() : '', // this will always return ''
      },
    }
    return ajax(params)
      .mergeMap((response) => {
        const { name, refreshToken } = response.body
        if (refreshToken && name === 'TokenExpiredError') {
          const refreshParams = { ... }
          return ajax(refreshParams)
            .mergeMap((refreshResponse) => {
              setToken(refreshResponse.body.auth.token)
              const me = { ... }
              return authMeSuccess(me)
            })
            .catch(error => of(authMeFailure(error)))
        }
        const me = { ... }
        setToken(response.body.auth.token)
        return authMeSuccess(me)
      })
      .catch(error => of(authMeFailure(error)))
  })

我使用 js-cookie 获取和设置 cookie

编辑:我实际上准备了一个包含getToken、setToken和removeToken的授权库,如下

import Cookies from 'js-cookie'

export const isAuthenticated = () => {
  const token = Cookies.get('token')
  return !!token
}

export const getToken = () => Cookies.get('token')

export const setToken = token => Cookies.set('token', token)

export const removeToken = () => Cookies.remove('token')

是的,我本可以在 epics 上使用 setToken(),只是想直接测试 cookie 设置方法

更新:

更新#2:

好的,我想我设法让它工作了,事实证明我们需要 2 种类型的 cookie,服务器端(刷新时生成的)和客户端(坚持导航),所以我的原因无法在 epics 上获取令牌,因为它不是从服务器端传递的(至少这是我的理解)

受此问题的启发 comment github

yarn add cookie-parser

./server.js(您需要有自定义服务器才能执行此操作)

const cookieParser = require('cookie-parser')

...

server.use(cookieParser())

./pages/_document.js

export default class extends Document {
  static async getInitialProps(...args) {
    // ...args in your case would probably be req
    const token = args[0].req ? getServerToken(args[0].req) : getToken()

    return {
      ...
      token,
    }
  }

  render() {
    ...
  }
}

./lib/auth.js 或您放置令牌方法的任何地方

export const getServerToken = (req) => {
  const { token = '' } = req.cookies

  return token
}

export const getToken = () => {
  return Cookies.get('token') ? Cookies.get('token') : ''
}

我不是 100% 明白这是如何解决我的问题的,但我现在就这样了