0

我一直在尝试使用nextredux-observable来实现反应服务器端渲染,现在我想实现 auth

登录时

  • 点击登录
    • 签到
      • 设置登录类型
      • 设置登录数据
    • 调用后端 api 身份验证/登录
      • 如果响应说令牌已过期
        • 使用 refreshToken 调用支持的 api auth/refresh
        • 根据身份验证/刷新响应令牌设置 cookie
        • 根据身份验证/刷新响应设置身份验证数据
      • 别的
        • 根据身份验证/登录响应令牌设置 cookie
        • 根据身份验证/登录响应设置身份验证数据

关于访问需要身份验证的页面

  • 检查调用的 cookietoken
    • 如果存在
      • 调用支持的 api auth/me 进行授权
      • 如果响应说令牌已过期
        • 使用 refreshToken 调用支持的 api auth/refresh
        • 根据身份验证/刷新响应令牌设置 cookie
        • 根据 auth/refresh 设置 auth 数据
      • 别的
        • 根据 auth/me 响应设置 auth 数据
    • 别的
      • 重定向到登录

上述步骤发生在史诗内部,如下

/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()总是会返回'',总是会派发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的auth lib,如下

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

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

更新:

  • 似乎尽管它不在控制台 > 应用程序 > Cookies 中,但它存在于每个页面上,因为如果我console.log(getToken())在组件渲染方法中这样做,它正在打印正确的令牌
  • 但是每次我刷新页面时,它就消失了。有点像它被存储在一个 redux 状态,这很奇怪

更新#2:

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

4

1 回答 1

0

受此问题启发,在 github 上发表评论

yarn add cookie-parser

on ./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% 明白这是如何解决我的问题的,但我现在就这样吧

于 2018-03-22T11:17:25.397 回答