【问题标题】:jwt refresh token reactjwt 刷新令牌反应
【发布时间】:2021-06-03 10:18:44
【问题描述】:

我正在开发一个使用 JWT 进行身份验证的小型应用程序,但我不确定如何在令牌过期时刷新它。我的令牌在 15 分钟后过期,我在下面提供了有关我的 api 以及我如何使用它的详细信息。我有一个登录,它会生成一个access_token,它最终会过期,我的数据也会消失。如何刷新令牌?

这是我尝试过的:

登录时,我已将refresh tokenaccess_token 添加到区域设置存储中。如果您将刷新令牌发布到https://freddy.codesubmit.io/refresh api,它将返回access_token;但这没有用。

const refreshToken = getItem('refresh_token')

useEffect(() => {
if(response === null) {
  axios.post('https://freddy.codesubmit.io/refresh', {}, {headers: {Authorization: `Bearer ${refreshToken}`}})
   .then(res => {
    localStorage.setItem("token", res.data.access_token);
  })
  .catch(err => console.log(err))
}
}

关于 jwt api 的详细信息:

Retrieve the necessary data for the dashboard at 'https://freddy.codesubmit.io/dashboard'. 
This endpoint requires a 'Authorization: Bearer access_token' header. 
Use the access token that you retrieved from Login. 
Keep in mind that access tokens expire after 15 minutes. 
You may request a fresh access token by sending a POST request to https://freddy.codesubmit.io/refresh' 
with the 'Authorization: Bearer refresh_token' header.

我还没有完成刷新令牌部分,因为我不知道该怎么做,我认为这可能是问题所在?由于令牌过期而超时?

这是我的登录信息:

import React, {useContext, useState} from 'react';
import { useHistory } from 'react-router-dom'
import axios from 'axios';
import { AuthContext } from '../hooks/UserContext';
import Logo from '../images/Freddys_Logo.svg';
import '../css/Login.css';
  
const Login = () => {
  const [userError, setUserError] = useState("");
  const [passError, setPassError] = useState("");
  const {setLoggedIn} = useContext(AuthContext);
  let history = useHistory();
  const [authInfo, setAuthInfo] = useState({
    username: "",
    password: ""
  })

  const handleChange = e => {
    setAuthInfo({
      ...authInfo,
      [e.target.name]: e.target.value
    })
  }

  const handleSubmit = e => {
    e.preventDefault();
    axios.post('https://freddy.codesubmit.io/login', authInfo)
      .then(res => {
        setLoggedIn(true);
         localStorage.setItem("token", res.data.access_token);
         localStorage.setItem("refresh_token", res.data.refresh_token);
         history.push('/dashboard')
      })
      .catch(err => console.log(err))
  }

 return (
  <div className="wrapper">
    <div className="logoContainer">
    <div className="heading">
       <p>
         Freddy's
         <br/>
        Artisanal
        <br/>
        Halloween
        <br/>
        Candy Shop
       </p>
    </div>
      <div className="svgLogo">
        <img src={Logo} className="svgLogo" alt="image" />  
      </div>
    </div>
    <div className="inputContainer">
    <form method="POST" onSubmit={handleSubmit}>
      <input 
        name="username" 
        type="text" 
        value={authInfo.username} 
        placeholder="username" 
        onChange={handleChange} 
        className="input" 
      />
      <input 
        name="password" 
        type="password" 
        value={authInfo.password} 
        placeholder="************" 
        onChange={handleChange}  
        className="input" 
      />
      <input 
        type="submit"  
        value="Login" 
        className="submitButton"
      />
    </form>
    </div>
  </div>
 )
}

export default Login;

这是我用来获取数据的 api:useFetch.js

import { useEffect, useState } from "react";
import axios from "axios";
const useFetch = async => {
  const [response, setResponse] = useState(null);
  const [error, setError] = useState(null);

  const token = localStorage.getItem("token");

  useEffect(() => {
    async function fetchData() {
      try {
        const res = await axios.get(
          "https://freddy.codesubmit.io/dashboard"
        , {headers: {Authorization: `Bearer ${token}`}});

        setResponse(res);
      } catch (error) {
        setError(error, "err");
      }
    }

    fetchData();
  }, [token]);
  return { response, error };
};
export default useFetch;

这是我试图在其上显示数据的页面:Dashboard.jsx

import React, {useState, useContext, useEffect} from 'react';
import Layout from './Layout';
import Table from './Table';
import axios from 'axios';
import { useHistory } from 'react-router-dom'
import { AuthContext } from '../hooks/UserContext'
import useFetch from "../hooks/useFetch";
import Switch from "react-switch";
import BarChart from 'react-bar-chart';

import '../css/Dashboard.css'

const Dashboard = () => {
  const {} = useContext(AuthContext);
  const { response, error } = useFetch();
  const [checked, setChecked] = useState(false);
  const refreshToken = localStorage.getItem("refresh_token")


  const handleCheckedChange = () => {
    setChecked(!checked)
  }

  const lastSevenDays = [
    {text: 'yesterday', value: 500}, 
    {text: 'today', value: 1300},
    {text: 'day 3', value: 300},
    {text: 'day 4', value: 300}, 
    {text: 'day 5', value: 300},
    {text: 'day 6', value: 300}, 
    {text: 'day 7', value: 300}, 
  ];
  const lastTwelveMonths = [
    {text: 'this month', value: 500}, 
    {text: 'today', value: 1300},
    {text: 'day 3', value: 300},
    {text: 'day 4', value: 300}, 
    {text: 'day 5', value: 300},
    {text: 'day 6', value: 300}, 
    {text: 'day 7', value: 300}, 
  ];
  const margin = {top: 10, right: 20, bottom: 30, left: 40};

  console.log(error)

 return (
    <Layout>
        <h1>Dashboard</h1>
        <div className="container">
          <div className="item">
            <span className="textStyle">Today</span>
            <p>$1456 / 9 orders</p>
          </div>
          <div className="item">
            <span className="textStyle">Today</span>
            <p>$1456 / 9 orders</p>
          </div>
          <div className="item">
            <span className="textStyle">Today</span>
            <p>$1456 / 9 orders</p>
          </div>
        </div>

        <div className="revenueContainer">
          <div className="title">
          {!checked ? <h2>Revenue (last 7 days)</h2> : <h2>Revenue (last 12 months)</h2>}
          </div>
          <div className="toggle">
            <Switch 
              onChange={handleCheckedChange} 
              checked={checked} 
              onColor="#86d3ff"
              onHandleColor="#2693e6"
              uncheckedIcon={false}
              checkedIcon={true}
              boxShadow="0px 1px 5px rgba(0, 0, 0, 0.6)"
              activeBoxShadow="0px 0px 1px 10px rgba(0, 0, 0, 0.2)"
            />
          </div>
        </div>

        <div>
            <div style={{width: '100%'}}> 
            {!checked ? (
              <BarChart 
                ylabel=''
                width={600}
                height={300}
                margin={margin}
                data={lastSevenDays}
              />
              ) : !!checked ? (
                <BarChart 
                ylabel=''
                width={600}
                height={300}
                margin={margin}
                data={lastTwelveMonths}
              />
              ) : null}
            </div>
          </div>

        <h2>Bestsellers</h2>
        <Table bestsellers={response?.data.dashboard.bestsellers} /> 
    </Layout>
 )
}

export default Dashboard;

Dashboard.js 中的表格组件

import React from 'react';
import '../css/Table.css';

const Table = ({bestsellers}) => {
  if(bestsellers === undefined || null) {
    return <div> loading...</div>
  }
  return (
    <div className="tableContainer">
      <div className="headingContainer">
        <div className="tableHeader"><span className="tableHeading">Product Name</span></div>
          <div className="tableHeader"><span className="tableHeading">Price</span></div>
          <div className="tableHeader"><span className="tableHeading"># Units Sold</span></div>
          <div className="tableHeader"><span className="tableHeading">Revenue</span></div>
      </div>
      {bestsellers
         .slice(0, 3)
         .map(row => (
        <div className="rowContainer" key={row.product.id}> 
          <div className="tableItem">
            <span className="tableItemText">{row.product.name}</span>
          </div>
          <div className="tableItem">
            <span className="tableItemText">N/A</span>
          </div>
          <div className="tableItem">
            <span className="tableItemText">{row.units}</span>
          </div>
          <div className="tableItem">
            <span className="tableItemText">{row.revenue}</span>
          </div>
        </div>
      ))}
    </div>
  )
}

export default Table;

【问题讨论】:

  • 如果不是刷新令牌,res.data.refresh_token 是什么?

标签: javascript reactjs jwt


【解决方案1】:

只需在授权时设置一个小于 15 分钟的超时时间,并带有一个发送带有刷新令牌的请求的回调。然后,在获得新的之后,交换 auth_tokens。

【讨论】:

  • 道歉我忘了把我试过的问题,我已经更新了问题
  • 很难解释。有许多我们不知道的命名空间:变量、函数.. 但我已经勾勒出的想法:您只想在原始令牌到期之前获取刷新令牌(而不是来自没有任何依赖关系的 useEffect,这将在每次用户交互时发送请求!!!)。
猜你喜欢
  • 2016-03-05
  • 2016-06-25
  • 2021-04-20
  • 1970-01-01
  • 2021-04-06
  • 2017-10-11
  • 2016-10-14
  • 1970-01-01
  • 2018-09-29
相关资源
最近更新 更多