如何确保在使用之前设置了cookie?

huangapple go评论147阅读模式
英文:

How can I make sure a cookie is set before using it?

问题

我目前正在使用 Next.js 和 NestJS 开发 JWT 授权代码流。

这是我从前端发送到后端的 POST 请求:

const response = await fetch(
  'http://localhost:4000/auth/42/callback?code=' + code, { // code 是从 OAuth 服务器接收到的
    method: 'POST',
    mode: 'cors',
    headers: {
      'Content-Type': 'application/json',
    },
    credentials: 'include',
  }
);

一旦后端接收到请求,它将生成 JWT 并使用 response 将其发送回前端:

@Post('42/callback')
async Callback(@Query('code') code: string, @Res({passthrough: true}) res) {
  if (!code) {
    res.status(400).send('缺少 code');
    return;
  }

  try {
    const response = await this.authService.exchangeCodeForToken(code);
    const jwt = await this.authService.handleCallback(response);
    res.setHeader('Access-Control-Allow-Credentials', 'true');
    res.cookie('jwt', jwt, {
      sameSite: 'strict'
    });
    res.status(200).send();
  } catch (error) {
    console.error(error);
    res.status(500).send('内部服务器错误');
  }
}

浏览器成功设置了 jwt cookie,但我无法确保在使用之前它已被设置。
似乎在响应和设置 cookie 之间存在一小段延迟:

import jwtDecode from 'jwt-decode';
import { useCookies } from 'react-cookie';

const [ cookies ] = useCookies();

const jwt = cookies.jwt;
const jwtPayload: any = jwtDecode(jwt); // 这里 jwt 是未定义的
英文:

I'm currently working on a JWT authorization code flow using Next.js and NestJS.

This is the POST request I'm sending from the front to the back.

const response = await fetch(
  'http://localhost:4000/auth/42/callback?code=' + code, { // code is received from the OAuth server
    method: 'POST',
    mode: 'cors',
    headers: {
      'Content-Type': 'application/json',
    },
    credentials: 'include',
  }
);

Once the backend receives the request, it will generate the JWT and send it back to the front using response.

@Post('42/callback')
async Callback(@Query('code') code: string, @Res({passthrough: true}) res) {
  if (!code) {
    res.status(400).send('Missing code');
    return;
  }

  try {
    const response = await this.authService.exchangeCodeForToken(code);
    const jwt = await this.authService.handleCallback(response);
    res.setHeader('Access-Control-Allow-Credentials', 'true');
    res.cookie('jwt', jwt, {
      sameSite: 'strict'
    });
    res.status(200).send();
  } catch (error) {
    console.error(error);
    res.status(500).send('Internal server error');
  }
}

The browser successfully sets the jwt cookie, however I'm unable to find a way to make sure it is set before using it.
It seems that there is a small latency between the response and setting the cookie.

import jwtDecode from 'jwt-decode';
import { useCookies } from 'react-cookie';

const [ cookies ] = useCookies();

const jwt = cookies.jwt;
const jwtPayload: any = jwtDecode(jwt); // Here jwt is undefined

I've looked at the browser Network Profiler but I'm not able to see any latency.
如何确保在使用之前设置了cookie?

答案1

得分: 0

为了绕过延迟并确保只在设置后访问 cookie 值,您可以使用 useEffect 钩子。类似于这样:

import { useEffect } from 'react'
import jwtDecode from 'jwt-decode'
import { useCookies } from 'react-cookie'

function YourComponent() {
  const [cookies, setCookie] = useCookies()
  const jwt = cookies.jwt

  useEffect(() => {
    if (jwt) {
      const jwtPayload = jwtDecode(jwt);
      // 访问 jwtPayload 或在此处执行其他与 JWT 相关的操作
    }
  }, [jwt])

  // 组件的其余代码

  return <div>您的组件内容</div>
}

export default YourComponent;

或者,如果您喜欢的话,您还可以创建一个自定义钩子,类似于这样:

import { useEffect, useState } from 'react'
import jwtDecode from 'jwt-decode'
import { useCookies } from 'react-cookie'

function useJWT() {
  const [cookies] = useCookies()
  const [jwt, setJWT] = useState(null)
  const [jwtPayload, setJWTPayload] = useState(null)

  useEffect(() => {
    if (cookies.jwt) {
      setJWT(cookies.jwt)
    }
  }, [cookies.jwt])

  useEffect(() => {
    if (jwt) {
      const decodedPayload = jwtDecode(jwt)
      setJWTPayload(decodedPayload);
    } else {
      setJWTPayload(null)
    }
  }, [jwt])

  return jwtPayload
}

export default useJWT

请注意,这些代码示例中的注释和标签也已经被翻译。

英文:

To bypass the delay and to ensure that you access the cookie value only after it has been set, you can use the useEffect hook. Something like this..

import { useEffect } from &#39;react&#39;
import jwtDecode from &#39;jwt-decode&#39;
import { useCookies } from &#39;react-cookie&#39;

function YourComponent() {
  const [cookies, setCookie] = useCookies()
  const jwt = cookies.jwt

  useEffect(() =&gt; {
    if (jwt) {
      const jwtPayload: any = jwtDecode(jwt);
      // Access the jwtPayload or perform any other actions with the JWT here
    }
  }, [jwt])

  // Rest of your component code

  return &lt;div&gt;Your component content&lt;/div&gt;
}

export default YourComponent;

Alternatively you can also create a custom hook if you prefer. something like this...

import { useEffect, useState } from &#39;react&#39;
import jwtDecode from &#39;jwt-decode&#39;
import { useCookies } from &#39;react-cookie&#39;

function useJWT() {
  const [cookies] = useCookies()
  const [jwt, setJWT] = useState(null)
  const [jwtPayload, setJWTPayload] = useState(null)

  useEffect(() =&gt; {
    if (cookies.jwt) {
      setJWT(cookies.jwt)
    }
  }, [cookies.jwt])

  useEffect(() =&gt; {
    if (jwt) {
      const decodedPayload = jwtDecode(jwt)
      setJWTPayload(decodedPayload);
    } else {
      setJWTPayload(null)
    }
  }, [jwt])

  return jwtPayload
}

export default useJWT

答案2

得分: 0

我终于找到了解决方法。
显然,在某些情况下,react-cookie 不可靠(请参见这个问题或这个问题)。当添加新的 Cookie 时,useCookies 钩子不会更新。在此问题得到修复之前,最佳的解决方法是使用universal-cookie

这是它的样子:

import Cookies from 'universal-cookie';
import jwtDecode from 'jwt-decode';

const cookies = new Cookies();
const jwt = cookies.get('jwt');
const decodedPayload = jwtDecode(jwt);
英文:

I've finally found a solution to my problem.
Apparently, react-cookie is not reliable in some situations (see this issue or this one). The useCookies hook is not updating when a new cookie is added. While this issue isn't fixed the best workaround is to use universal-cookie instead.

Here is what it will looks like:

import Cookies from &#39;universal-cookie&#39;;
import jwtDecode from &#39;jwt-decode&#39;;

const cookies = new Cookies();
const jwt = cookies.get(&#39;jwt&#39;);
const decodedPayload = jwtDecode(jwt);

huangapple
  • 本文由 发表于 2023年7月11日 03:38:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/76656817.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定