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

Posted

技术标签:

【中文标题】下一个使用 cookie 的 js redux-observable 持久认证令牌【英文标题】:next js redux-observable persistent auth token using cookie 【发布时间】:2018-08-29 03:47:09 【问题描述】:

我一直在尝试使用next 和redux-observable 实现react 服务器端渲染,现在我想实现身份验证

登录时

点击登录 调度登录 设置登录类型 设置登录数据 调用后端api auth/signin 如果响应显示令牌已过期 使用 refreshToken 调用支持的 api 身份验证/刷新 根据身份验证/刷新响应令牌设置 cookie 根据身份验证/刷新响应设置身份验证数据 其他 根据身份验证/登录响应令牌设置 cookie 根据身份验证/登录响应设置身份验证数据

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

检查名为 token 的 cookie 如果存在 调用支持的 api auth/me 进行授权 如果响应显示令牌已过期 使用 refreshToken 调用支持的 api 身份验证/刷新 根据身份验证/刷新响应令牌设置 cookie 根据身份验证/刷新设置身份验证数据 其他 根据身份验证/我的响应设置身份验证数据 其他 重定向到登录

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

/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) 将始终派发 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 获取和设置cookies

编辑:我实际上准备了一个包含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:

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

【问题讨论】:

您可以尝试从 Cookies.set 中删除 path: '/' 吗?只是为了确保路径没有问题。 哇!你是对的,它的路径,我现在很为自己感到羞耻,谢谢btw! 不,很抱歉它仍然无法正常工作,不知道它以前的工作情况如何 尝试删除所有 Cookies.set 中的 path 选项 另外能否提供 getToken() 的代码? 我确实删除了所有 path 选项,顺便说一句,问题已用 lib/auth.js 更新 【参考方案1】:

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

【讨论】:

以上是关于下一个使用 cookie 的 js redux-observable 持久认证令牌的主要内容,如果未能解决你的问题,请参考以下文章

JS 中 cookie 的使用

JS 中 cookie 的使用

js中cookie的使用详细分析

jquery.cookie() 方法的使用(读取写入删除)

关于js-cookie使用出现兼容性问题以及js-cookie的如何使用

js操作cookie