#reactjs #express #jwt #mern #bearer-token
Вопрос:
Я разрабатываю электронную коммерцию как упражнение для полного набора, и у меня возникла эта проблема. Особенность в том, что ошибка возникает только в этом случае: если я запускаю приложение, не входя в систему, а затем вхожу в систему (если я делаю консоль.журнал токена, сохраненный в файлах cookie, возвращает значение null). Если я обновлю страницу, все снова будет работать и в этом случае.
Я попытался проверить токены на jwt.io и они правы.
Это код части входа и входа в систему с помощью контроллера Google, в которой я создаю токен:
import validator from 'validator';
import bcrypt from 'bcrypt';
import jwt from 'jsonwebtoken';
import {OAuth2Client} from 'google-auth-library';
import sgMail from '@sendgrid/mail';
import dotenv from 'dotenv';
import {User} from '../models/User.js';
//LOADING ENVIRONMENT VARIABLE
dotenv.config();
const JWT_CONFIRM_ACCOUNT = process.env.JWT_CONFIRM_ACCOUNT;
const JWT_SECRET = process.env.JWT_SECRET;
const JWT_EXPIRE = process.env.JWT_EXPIRE;
const CLIENT_URL = process.env.CLIENT_URL;
const SGMAIL_API_KEY = process.env.SGMAIL_API_KEY;
const JWT_RESET_PASSWORD = process.env.JWT_RESET_PASSWORD;
const JWT_EMAIL_FROM = process.env.JWT_EMAIL_FROM;
//SETTING SGMAIL APIKEY
sgMail.setApiKey(SGMAIL_API_KEY);
//SIGN-IN
export const signIn = async (req, res) => {
const { email, password } = req.body;
try {
const user = await User.findOne({email});
if(!user){
return res.status(400).json({errorMessage : 'Invalid credentials'})
}
if(!email || !password){
return res.status(400).json({errorMessage: 'All fields are required'})
}
if(!validator.isEmail(email)){
return res.status(400).json({errorMessage : 'Invalid email'})
}
//JWT
const payload = {
user : {
_id : user._id
}
}
const isMatch = await bcrypt.compare(password, user.password);
if(!isMatch){
return res.status(400).json({errorMessage: 'Invalid credentials'})
}
else{
jwt.sign(
payload,
JWT_SECRET,
{expiresIn: JWT_EXPIRE},
(err, token) => {
if(err) console.log ('Jwt error: ', err);
const {_id, username, email, role} = user;
res.json({
token,
user : {_id, username, email, role}
})
}
)
}
} catch (error) {
return res.status(500).json({errorMessage : `${error}`})
}
}
//GOOGLE LOGIN
export const googleLogin = (req, res) => {
const {token} = req.body;
const client = new OAuth2Client('203822999175-ic2e949ccriqa983otoa5949dodi7iif.apps.googleusercontent.com');
client.verifyIdToken({idToken: token, audience: '203822999175-ic2e949ccriqa983otoa5949dodi7iif.apps.googleusercontent.com'})
.then(response => {
const{email_verified, name, email, picture: userImage, given_name: firstName, family_name: lastName} = response.payload;
if(email_verified){
User.findOne({email}).exec((err, user) => {
if(user){
user.image = userImage;
const payload = {user : {
_id : user._id
}}
const token = jwt.sign( payload, JWT_SECRET, {expiresIn: JWT_EXPIRE});
const {_id, email, username, role} = user;
return res.json({
token,
user: {_id, email, username, role, userImage, firstName, lastName}
})
}else{
let password = email JWT_SECRET;
user = new User({
username: firstName, email, password, image: userImage
});
user.save((err, save) => {
if(err){
return res.status(400).json({errorMessage: `${err}` })
}
const token = jwt.sign({_id: user._id}, JWT_SECRET, {expiresIn: JWT_EXPIRE});
const {_id, email, username, role} = user;
const emailData = {
from: JWT_EMAIL_FROM,
to: email,
subject: "Account created - Tea Store",
html: `
<h1>Hi ${user.username}! Your account has been created</h1>
<p style = {{fontWeight : 'bold'}}>Thanks for logging in with google.
To access the site via our custom sign-in form, choose a password for your account at the following link:</p>
<hr/>
<p>${CLIENT_URL}</p>
`
}
sgMail.send(emailData, (err, sent) => {
if(err){
return res.json({errorMessage: `${err}`})
}
})
return res.status(200).json({
token,
user: {_id, email, username, role, userImage, firstName, lastName},
successMessage: 'Account successfully created! Check your mailbox'
})
})
}
})
}else{
return res.status(400).json({errorMessage: 'Google login failed'})
}
}).catch(err => {
return res.status(500).json({errorMessage: 'Server Error'})
})
}
Код входа и входа в систему с помощью части маршрута Google:
import express from 'express';
import {signUp, signIn, googleLogin, forgotPassword, resetPassword, accountAuth} from '../controllers/auth.js';
const router = express.Router();
router.route('/sign-up').post(signUp);
router.route('/account-authentication/:token').post(accountAuth);
router.route('/sign-in').post(signIn);
router.route('/google-login').post(googleLogin);
router.route('/forgot-password').post(forgotPassword);
router.route('/reset-password/:token').post(resetPassword);
export default router;
Файл сервера:
import express from 'express';
import mongoose from 'mongoose';
import cors from 'cors';
import dotenv from 'dotenv';
import authRouter from './routes/auth.js';
import categoryRouter from './routes/category.js';
import productRouter from './routes/product.js';
//DOTENV CONFIG
dotenv.config();
const MONGODB_CONNECTION = process.env.MONGO_URI;
//INITIALIZE APP
const app = express()
//MIDDLEWARES
/*app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "http://localhost:3000");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});*/
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cors({
origin: 'http://localhost:3000',
methods: ['GET','POST','DELETE','UPDATE','PUT','PATCH']
}));
//ROUTES
app.use('/api/auth', authRouter);
app.use('/api/categories', categoryRouter);
app.use('/api/products', productRouter)
//PORT
const PORT = process.env.PORT || 5020
//CONNECT MONGODB
const connectDB = () => {
mongoose.connect(MONGODB_CONNECTION, {
useNewUrlParser: true,
useFindAndModify: true,
useUnifiedTopology: true,
useCreateIndex: true
} )
.then(() => console.log('MONGODB is connected'))
.catch(err => console.log('MONGODB connection error:', err ))
}
connectDB();
//INITIALIZE SERVER
app.listen(PORT, () => console.log (`Connection is established and running on port ${PORT}`)
)
Authorization middlewares:
import jwt from 'jsonwebtoken';
import dotenv from 'dotenv';
import {User} from '../models/User.js';
dotenv.config();
const JWT_SECRET = process.env.JWT_SECRET;
export const authMiddleware = async (req, res, next) => {
try {
let token;
if(req.headers.authorization amp;amp; req.headers.authorization.startsWith('Bearer')){
token = req.headers.authorization.split(" ")[1]
}
if(!token){
return res.status(401).json({errorMessage : "Invalid Authentication"})
}
try {
const decoded = jwt.verify(token, JWT_SECRET);
console.log(decoded)
const user = await User.findById(decoded._id || decoded.user._id);
if(!user){
return res.status(404).json({errorMessage: "No user found"})
}
req.user = user;
next()
} catch (error) {
return res.status(500).json({errorMessage: error.message})
}
}catch (error) {
return res.status(500).json({errorMessage: "Not authorized"})
}
}
export const authAdminMiddleware = async (req, res, next) => {
try {
const user = await User.findOne({
_id: req.user.id
})
if(req.user.role === 0){
return res.status(400).json({errorMessage: "Not Authorized. Admin private route."})
}
next()
} catch (error) {
return res.status(401).json({errorMessage: 'Not Authorized. Admin private route.'})
}
}
General frontend configuration of API calls:
import axios from 'axios';
import { getCookies } from '../helpers/storageamp;cookies/storageamp;cookies';
const config = {
headers : {
'Content-Type' : 'application/json',
'Authorization' : 'Bearer ' getCookies('token')
}
}
export const signup = async (data) => {
const response = await axios.post('http://localhost:5020/api/auth/sign-up', data, config);
return response;
};
export const accountAuth = async (data) => {
const response = await axios.post('http://localhost:5020/api/auth/account-authentication/:token', data, config);
return response;
}
export const signin = async (data) => {
const response = await axios.post('http://localhost:5020/api/auth/sign-in', data, config);
return response;
};
export const googleLogin = async (data) => {
const response = await axios.post('http://localhost:5020/api/auth/google-login', data, config);
return response;
}
export const forgotPassword = async (data) => {
const response = await axios.post('http://localhost:5020/api/auth/forgot-password', data, config);
return response;
}
export const resetPassword = async (data) => {
const response = await axios.post('http://localhost:5020/api/auth/reset-password/:token', data, config);
return response;
}
import axios from 'axios';
import { getCookies } from '../helpers/storageamp;cookies/storageamp;cookies';
console.log(getCookies('token'))
const config = {
headers : {
'Content-Type' : 'application/json',
'Authorization' : 'Bearer ' getCookies('token')
}
}
export const fetchProducts = async () => {
const response = await axios.get('http://localhost:5020/api/products/get-products');
return response;
};
export const postProduct = async (data) => {
const response = await axios.post('http://localhost:5020/api/products/create-product', data, config);
return response;
}
Предполагая, что регистрация и вход работают идеально, сталкивался ли кто-нибудь с этой проблемой раньше?