访问令牌给予承诺



所以我使用访问和刷新令牌进行jwt身份验证。但问题是,当访问令牌到期,我生成一个新的访问令牌在前端(反应)。它给了我一个承诺

backend/routes/auth.js(刷新令牌的路由以及生成刷新令牌并存储它的位置(登录路由))


router.post("/login", async (req, res) => {
try {
// Validating user
const { error } = loginValidation(req.body);
if (error) return res.status(400).json(error.details[0].message);
// Making sure email is correct
const user = await User.findOne({ email: req.body.email });
if (!user) return res.status(400).json("Invalid email or password");
// Making sure the password is correct
const validPass = await bcrypt.compare(req.body.password, user.password);
if (!validPass) return res.status(400).json("Invalid email or password");
const userPayload = {
_id: user._id,
displayname: user.displayname,
username: user.username,
email: user.email,
bookmarkedTweets: user.bookmarkedTweets,
likedTweets: user.likedTweets,
followers: user.followers,
following: user.following,
date: user.date,
month: user.month,
day: user.day,
year: user.year,
profilePic: user.profilePic,
};
// Generating access token
const accessToken = generateAccessToken(userPayload);
// Generating refresh token
const refreshToken = jwt.sign(
user.toJSON(),
process.env.REFRESH_TOKEN_SECRET
);
// Getting info for refresh token
const newRefreshToken = new RefreshToken({
refreshToken: refreshToken,
});
// Saving refresh token into db
await newRefreshToken.save();
res.json({
_id: user._id,
displayname: user.displayname,
username: user.username,
email: user.email,
password: user.password,
bookmarkedTweets: user.bookmarkedTweets,
likedTweets: user.likedTweets,
followers: user.followers,
following: user.following,
date: user.date,
month: user.month,
day: user.day,
year: user.year,
profilePic: user.profilePic,
accessToken: accessToken,
refreshToken: refreshToken,
});
} catch (error) {
res.sendStatus(500);
console.log(error);
}
});

router.post("/refresh/token", async (req, res) => {
try {
// Getting refresh token
const refreshToken = req.body.token;
// Finding refresh token
const _refreshToken = await RefreshToken.findOne({ refreshToken: refreshToken });
// Making sure there is a refresh token and that refresh token exists in db
if (refreshToken == null) return res.sendStatus(401);
if (!_refreshToken) return res.sendStatus(403);
// Vaifying refresh token
jwt.verify(refreshToken, process.env.REFRESH_TOKEN_SECRET, (err, user) => {
if (err) return res.sendStatus(403);
const userPayload = {
_id: user._id,
displayname: user.displayname,
username: user.username,
email: user.email,
bookmarkedTweets: user.bookmarkedTweets,
likedTweets: user.likedTweets,
followers: user.followers,
following: user.following,
month: user.month,
day: user.day,
year: user.year,
date: user.date,
profilePic: user.profilePic,
};
// Generating access token
const accessToken = generateAccessToken(userPayload);
res.json({ accessToken });
});
} catch (error) {
res.sendStatus(500);
}
});

后端/中间件)/authenticateToken.js

const jwt = require("jsonwebtoken");
require("dotenv").config();
module.exports = function authenticateToken(req, res, next) {
const authHeader = req.headers["authorization"]; // Getting auth header
const token = authHeader && authHeader.split(" ")[1]; // Getting access token from auth header
if (token == null) return res.sendStatus(401);
jwt.verify(token, process.env.ACCESS_TOKEN_SECRET, (err, user) => {
if (err) return res.sendStatus(403); // Making sure the token is valid
req.user = user;
next();
});
};

后端/跑龙套generateAccessToken.js

const jwt = require("jsonwebtoken");
require("dotenv").config();
module.exports = function (user) {
return jwt.sign(user, process.env.ACCESS_TOKEN_SECRET, { expiresIn: "15s" });
};

前端/src/api/axios.js

import axios from "axios";
const BASE_URL = "http://localhost:5000";
const accessToken = sessionStorage.getItem("accessToken");
const refreshToken = localStorage.getItem("refreshToken");
export default axios.create({
baseURL: BASE_URL,
headers: { "Content-Type": "application/json" },
});
const client = axios.create({ baseURL: BASE_URL });
export const axiosAuth = async ({ ...options }) => {
// Sending access token with request
client.defaults.headers.common.Authorization = `Bearer ${accessToken}`;
const onSuccess = (response) => response;
const onError = (error) => {
if (error.response.status === 403) {
// Making function to generate new access token
const refresh = async () => {
const { data } = await axios.post(`${BASE_URL}/auth/refresh/token`, {
token: refreshToken,
});
return data;
};
// Generating access token
const newAccessToken = refresh();
sessionStorage.setItem("accessToken", newAccessToken);
return client({ ...options });
}
throw error;
};
return client(options).then(onSuccess).catch(onError);
};

frontend/src/modals/Tweet.modal.js(这里我使用axiosAuth)

import React, { useState } from "react";
import AccountCircleOutlinedIcon from "@mui/icons-material/AccountCircleOutlined";
import ArrowBackIcon from "@mui/icons-material/ArrowBack";
import PublicOutlinedIcon from "@mui/icons-material/PublicOutlined";
import CollectionsOutlinedIcon from "@mui/icons-material/CollectionsOutlined";
import GifBoxOutlinedIcon from "@mui/icons-material/GifBoxOutlined";
import BarChartOutlinedIcon from "@mui/icons-material/BarChartOutlined";
import SentimentSatisfiedAltOutlinedIcon from "@mui/icons-material/SentimentSatisfiedAltOutlined";
import ScheduleOutlinedIcon from "@mui/icons-material/ScheduleOutlined";
import LocationOnOutlinedIcon from "@mui/icons-material/LocationOnOutlined";
import Loader from "../components/Loader/Loader.comp";
import { useDispatch, useSelector } from "react-redux";
import {
setTweetModal,
setTweetPending,
tweetErrorClear,
tweetFail,
} from "../features/tweet.slice";
import { axiosAuth } from "../api/axios";
function Tweet() {
const [textfield, setTextfield] = useState("");
const { user } = useSelector((state) => state.user);
const { tweetModalIsOpen, error, isLoading } = useSelector(
(state) => state.tweet
);
const { profilePic } = user;
const dispatch = useDispatch();
if (error !== "") {
setTimeout(() => dispatch(tweetErrorClear()), 3000);
}
const handleOnClick = async () => {
dispatch(setTweetPending(true));
try {
await axiosAuth({
url: "/posts/create",
method: "POST",
body: { textfield },
});
} catch (error) {
dispatch(tweetFail(error.response.data));
}
};
return (
<div
className={
tweetModalIsOpen
? `h-screen w-screen absolute inset-0 bg-white py-2 px-4`
: `hidden`
}
>
<div className="flex-items justify-between">
<div
className="p-1 cursor-pointer rounded-full hover:bg-gray-200 transition-color"
onClick={() => dispatch(setTweetModal(false))}
>
<ArrowBackIcon style={{ fontSize: "1.5rem" }} />
</div>
<button
className="py-1 px-4 transition-color rounded-full bg-blue-500 text-white font-bold hover:bg-blue-600"
onClick={() => handleOnClick()}
>
{isLoading ? <Loader forPage={false} /> : <h1>Tweet</h1>}
</button>
</div>
<div className="flex mt-6 space-x-2">
{profilePic === "" ? (
<AccountCircleOutlinedIcon style={{ fontSize: "2rem" }} />
) : (
<img src={profilePic} alt="profile_pic" />
)}
<div>
<textarea
name="tweet"
id="tweet"
rows="4"
value={textfield}
onChange={(e) => setTextfield(e.target.value)}
className="w-screen outline-none text-xl text-gray-700 placeholder:text-gray-600"
placeholder="What's happening?"
></textarea>
<div className="flex-items space-x-2 text-blue-400 font-bold py-0.5 px-2 rounded-full hover:bg-blue-50 transition-color cursor-pointer w-max">
<PublicOutlinedIcon style={{ fontSize: "1.5rem" }} />
<h1>Everyone can reply</h1>
</div>
<div className="ring-1 ring-gray-100 my-2 w-[75%]" />
<div className="flex-items space-x-2 text-blue-500">
<div className="tweet-icon">
<CollectionsOutlinedIcon style={{ fontSize: "1.5rem" }} />
</div>
<div className="tweet-icon">
<GifBoxOutlinedIcon style={{ fontSize: "1.5rem" }} />
</div>
<div className="tweet-icon">
<BarChartOutlinedIcon style={{ fontSize: "1.5rem" }} />
</div>
<div className="tweet-icon">
<SentimentSatisfiedAltOutlinedIcon
style={{ fontSize: "1.5rem" }}
/>
</div>
<div className="tweet-icon">
<ScheduleOutlinedIcon style={{ fontSize: "1.5rem" }} />
</div>
<div className="tweet-icon">
<LocationOnOutlinedIcon style={{ fontSize: "1.5rem" }} />
</div>
</div>
</div>
</div>
{error && <h1 className="error err-animation">{error}!</h1>}
</div>
);
}
export default Tweet;

提前感谢!

我假设_refreshToken是您所指的承诺。为了获得该承诺的最终值(即刷新令牌本身),将async添加到中间件函数中,并将await添加到赋值语句中:

router.post("/refresh/token", async (req, res) => {
try {
const refreshToken = req.body.token;
const _refreshToken = await RefreshToken.findOne({ refreshToken: refreshToken });

frontend/src/api/axios.js相同:

const onError = async (error) => {
...
const newAccessToken = await refresh();

最新更新