目前,我有一个通过用户邮箱发送的身份验证URL,其中包含以下令牌:"http://localhost:5173/activation/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI2NWZkNmM0OTMyOWI4YzhjNjFjMjJiY2YiLCJpYXQiOjE3MTExMDcxNDUsImV4cCI6MTcxMTE5MzU0NX0.BLkEkRtRxYk3uKKobWRuD0rsf7qob35l5-OmdJfRqyU"
现在的问题是,我试图使用useParams()
%的Reaction-Router-DOM来获取令牌("active/"之后的字符串).如果该字符串不包括像"."
这样的字符,那么我会得到"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"
,但是如果一个完整的令牌像上面的"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI2NWZkNmM0OTMyOWI4YzhjNjFjMjJiY2YiLCJpYXQiOjE3MTExMDcxNDUsImV4cCI6MTcxMTE5MzU0NX0.BLkEkRtRxYk3uKKobWRuD0rsf7qob35l5-OmdJfRqyU"
一样,那么我就不会得到完整的令牌值.
Routes/auth.js
const express = require("express");
const authController = require("../controllers/auth");
const router = express.Router();
router.post("/signup", authController.postSignup);
router.post("/activation", authController.activateAccount);
module.exports = router;
controllers/auth.js
const bcrypt = require("bcrypt");
const User = require("../models/user");
const { v4: uuidv4 } = require("uuid");
const jwt = require("jsonwebtoken");
const { getAuth } = require("firebase-admin/auth");
const emailRegex = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/; // regex for email
const passwordRegex = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{6,20}$/; // regex for password
const sendMail = require("../utils/sendMail");
const generateUserName = async (email) => {
let username = email.split("@")[0];
const isUsernameExists = await User.exists({
"personal_info.username": username
});
if (isUsernameExists) {
username += uuidv4().substring(0, 5);
}
return username;
};
const fortmatDataToSend = (user) => {
const access_token = jwt.sign(
{ id: user._id },
process.env.SECRET_ACCESS_KEY,
{ expiresIn: "1h" }
);
return {
access_token,
_id: user._id,
profile_img: user.personal_info.profile_img,
username: user.personal_info.username,
fullname: user.personal_info.fullname
};
};
exports.postSignup = async (req, res) => {
const { fullname, email, password } = req.body;
try {
if (fullname.length < 3) {
return res
.status(403)
.json({ error: "Fullname must be at least 3 letters long !" });
}
if (!email.length) {
return res.status(403).json({ error: "Enter Email" });
}
if (!emailRegex.test(email)) {
return res.status(403).json({ error: "Invalid email address" });
}
if (!passwordRegex.test(password)) {
return res.status(403).json({
error:
"Password should be 6 to 20 characters long with a numeric, 1 lowercase and 1 uppercase letters!"
});
}
const existingUser = await User.findOne({ email: email }).exec();
if (existingUser) {
return res.status(409).json({ error: "Email is already registered" });
}
const hashedPassword = await bcrypt.hash(password, 12);
const username = await generateUserName(email);
const user = new User({
personal_info: {
fullname,
email,
password: hashedPassword,
username,
active: false
}
});
const activation_token = jwt.sign(
{ userId: user._id },
process.env.SECRET_ACCESS_KEY,
{ expiresIn: "1d" }
);
const activationLink = `${process.env.CLIENT}/activation/${activation_token}`;
await sendMail({
email: email,
subject: "Activate Your Account",
message: `
<p>Hello ${fullname} 👋, Please click following link to active your account ⬇️</p>
<a href="${activationLink}">Verify Your Email</a>
`
});
await user.save();
return res.status(200).json({
status:
"Registration successful. Please check your email for activation link."
});
} catch (err) {
if (err.code === 11000) {
return res.status(409).json({ error: "Email is already registered!" });
}
return res.status(500).json({ error: err.message });
}
};
exports.activateAccount = async (req, res) => {
try {
const { activation_token } = req.body;
const decodedToken = jwt.verify(
activation_token,
process.env.SECRET_ACCESS_KEY
);
const userId = decodedToken.userId;
const user = await User.findById(userId);
if (!user) {
return res.status(404).json({ error: "User not found" });
}
if (user.personal_info.active) {
return res.status(400).json({ error: "Account already activated" });
}
user.personal_info.active = true;
await user.save();
return res.status(200).json({ message: "Account activated successfully" });
} catch (error) {
if (error.name === "TokenExpiredError") {
return res.status(400).json({ error: "Activation token expired" });
} else if (error.name === "JsonWebTokenError") {
return res.status(400).json({ error: "Invalid activation token" });
}
return res.status(500).json({ error: "Internal server error" });
}
};
服务器前端代码️
App.js
import { Route, Routes } from "react-router-dom";
import Navbar from "./components/navbar.component";
import UserAuthForm from "./pages/userAuthForm";
import UserContextProvider from "../context/user-context";
import Editor from "./pages/editor";
import Activation from "./pages/Activation";
const App = () => {
return (
<UserContextProvider>
<Routes>
<Route path="/" element={<Navbar />}>
<Route path="signin" element={<UserAuthForm type="signin" />}></Route>
<Route path="signup" element={<UserAuthForm type="signup" />}></Route>
</Route>
<Route path="/editor" element={<Editor />} />
<Route path="/activation/:activation_token" element={<Activation />} />
</Routes>
</UserContextProvider>
);
};
export default App;
Activation.jsx
import axios from "axios";
import { useEffect, useState } from "react";
import { useLocation, useParams } from "react-router-dom";
const Activation = () => {
const { activation_token } = useParams();
const [error, setError] = useState(false);
const [loading, setLoading] = useState(true);
useEffect(() => {
if (activation_token) {
const activateAccount = async () => {
try {
await axios.post(
`http://localhost:3000/activation/${activation_token}`
);
} catch (error) {
setError(true);
setLoading(false);
}
};
activateAccount();
}
}, [activation_token]);
return (
<div>
{loading ? (
<p>Loading...</p>
) : error ? (
<div>
<h1>Activation Error</h1>
<p>
There was an error activating your account. Please try again later.
</p>
</div>
) : (
<div>
<h1>Account Activated Successfully</h1>
<p>Your account has been successfully activated.</p>
</div>
)}
</div>
);
};
export default Activation;
我不知道问题出在哪里.我试图使用useParams()
获取令牌("activation/"
之后的字符串),但如果该字符串不包括"."
这样的字符,那么我就得到(例如"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"
),但如果完整的令牌是如上所述,我就没有得到它.我从useParams
中提取了console.log(activation_token)
.