我是一名学生,我正在尝试创建一个使用 React 登录/注册的聊天应用程序,但我似乎无法在刷新页面时让用户保持登录状态。谁能帮帮我?提前谢谢你。
登录.jsx
import React, { useEffect, useState, useContext } from "react";
import { useNavigate, Link } from "react-router-dom";
import logo1 from "../images/logo1.png";
import Chat from "./Chat";
import man from "../images/aolemoji.png";
import { UserContext } from "../context/UserContext";
import axios from "axios";
import App from "../App";
import io from "socket.io-client";
const Login = (props) => {
const { user, setUser, socket } = useContext(UserContext);
const [userToken, setuserToken] = useState("");
const navigate = useNavigate();
const [state, setState] = useState({
login: {
email: "",
password: "",
},
});
const [errors, setErrors] = useState([]);
const { login } = state;
const handleLoginInputs = (e) => {
props.setAuthorized("");
setState({
...state,
login: { ...state.login, [e.target.name]: e.target.value },
});
};
const handleLogin = async (e) => {
e.preventDefault();
const errorArr = [];
axios
.post("http://localhost:8000/api/users/login", login, {
withCredentials: true,
})
.then((res,req) => {
setUser({
id: res.data.userInfo.id,
screenName: res.data.userInfo.screenName,
});
console.log("Printing out res.data during login", res.data);
console.log("User has been successfully logged in");
console.log("What is my token?", res.data.token);
navigate("/chat");
})
.catch((err) => {
console.log("is it even catching an error?", err);
const errorResponse = err.response.data;
console.log("errorArr", errorArr);
console.log("errorResponse", errorResponse);
errorArr.push(
"Ooops, something went wrong with logging in. Try again!"
);
setErrors(errorArr);
console.log("what is my error arr?", errorArr);
});
};
return (
<>
<div className="">
<nav className=" whitespace-nowrap m-2 border-gray-200 px-2 sm:px-4 py-2.5 rounded-sm shadow-lg fill-indigo-400border-2 bg-blue-400">
<div className="container flex flex-wrap items-center justify-between mx-auto">
<div className="flex items-center">
<img
src={man}
className=" h-20 w-25"
alt="Flowbite Logo"
/>
<h1 className="text-4xl content-centerfont-extrabold text-white dark:text-white">
SAIM - MESSENGER 👋
</h1>
</div>
<p className="tracking-tighter text-gray-900 md:text-lg dark:text-gray-900">
A space where millennials can chat and share their
hilarious away messages
</p>
<div
className="hidden w-full md:block md:w-auto"
id="navbar-default"
></div>
</div>
</nav>
</div>
<div className="items-center flexm-2">
<span className=" block max-w-xs max-h-sm p-2 bg-white border border-gray-200 rounded-lg shadow hover:bg-gray-100 dark:border-gray-700 mt-2 m-auto">
<img src={logo1} style={{}} alt="logo1" />
<hr />
<form onSubmit={handleLogin}>
{errors.length > 0 &&
errors.map((error, i) => (
<>
<p className=" text-red-600" key={i}>
{error}
</p>
</>
))}
<div className="mb-6 mt-0">
<label className="block">
<span className="after:content-['*'] after:ml-0.5 after:text-red-500 flex text-sm font-medium text-black">
eMail! 🔑
</span>
<input
onChange={handleLoginInputs}
type="email"
name="email"
className="mt-1 px-3 py-2 bg-white border shadow-sm border-slate-300 placeholder-slate-400 focus:outline-none focus:border-sky-500 focus:ring-sky-500 block w-full rounded-md sm:text-sm focus:ring-1"
placeholder="[email protected]"
/>
<Link
className=" text-blue-700 underline"
to={"/register"}
>
No account? Sign Up!
</Link>
</label>
</div>
<div>
<label className="block">
<span className="after:content-['*'] after:ml-0.5 after:text-red-500 block text-sm font-medium text-black">
PaSsWoRd:
</span>
<input
onChange={handleLoginInputs}
type="text"
name="password"
className="mt-1 px-3 py-2 bg-white border shadow-sm border-slate-300 placeholder-slate-400 focus:outline-none focus:border-sky-500 focus:ring-sky-500 block w-full rounded-md sm:text-sm focus:ring-1"
placeholder="Enter Your Password"
/>
</label>
</div>
<button type="submit" className="m-8 flex">
<a
href="#_"
className="relative px-6 py-3 font-bold text-black group"
type="submit"
>
<span className="absolute inset-0 w-full h-full transition duration-300 ease-out transform -translate-x-2 -translate-y-2 bg-blue-300 group-hover:translate-x-0 group-hover:translate-y-0"></span>
<span className="absolute inset-0 w-full h-full border-4 border-black"></span>
<span className="relative">Sign On</span>
</a>
</button>
<hr />
<span className="text-sm text-gray-500 sm:text-center dark:text-gray-400">
© 2023{" "}
<a
href="https://flowbite.com/"
className="hover:underline"
>
SAIM MESSENGER™
</a>
. All Rights Reserved.{" "}
</span>
</form>
</span>
</div>
</>
);
};
export default Login;
用户.controller.js
const User = require("../models/user.models");
const jwt = require("jsonwebtoken");
const bcrypt = require("bcrypt");
function helper(message, value) {
console.log(message, value);
return value;
}
module.exports = {
findAllUsers: (req, res) => {
User.find()
.then((allUsers) =>
res.json({ allUsers, message: "Here are all users" })
)
.catch((err) =>
res.status(400).json({
message:
"Something went wrong while trying to view all users",
error: err,
})
);
},
updateUser: (req, res) => {
User.findByIdAndUpdate(req.params.id, req.body, {
new: true,
runValidators: true,
})
.then((updatedAwayMessage) =>
res.json({
updatedAwayMessage,
message: "You have successfully updated a user profile.",
})
)
.catch((err) =>
res.status(400).json({
message: "Something went wrong while user update.",
error: err,
})
);
},
findOneUser: (req, res) => {
User.findById(req.params.id)
.then((user) =>
res.json({
user,
message: "Yay you have found a specific user",
})
)
.catch((err) =>
res.status(400).json({
message:
"Something went wrong while trying to find details of a user",
error: err,
})
);
},
register: (req, res) => {
User.create(req.body)
.then((user) => {
const userToken = jwt.sign(
{
id: user._id,
},
process.env.SECRET_KEY
);
res.cookie("usertoken", userToken, {
httpOnly: true,
// secure: true,
// sameSite: 'none',
// expires: new Date(Date.now() + 24 * 60 * 60 * 1000) // 24 hours
}).json({ msg: "Successful Registration!", user: user });
})
.catch((err) =>
res.json({ message: "Problem with registration", error: err })
);
},
deleteUser: (req, res) => {
User.findByIdAndDelete(req.params.id)
.then((deletedUser) =>
res.json({ deletedUser, message: "Successfully deleted user." })
)
.catch((err) =>
res.status(400).json({
message: "Something went wrong while deleting/adopting.",
error: err,
})
);
},
login: async (req, res) => {
const user = await User.findOne({ email: req.body.email });
if (user === null) {
// email not found in users collection
return res
.sendStatus(400)
.json({ message: "Invalid email address" });
}
// if we made it this far, we found a user with this email address
// let's compare the supplied password to the hashed password in the database
const correctPassword = await bcrypt.compare(
req.body.password,
user.password
);
if (!correctPassword) {
// password wasn't a match!
return res.sendStatus(400).json({ message: "Invalid password" });
}
// if we made it this far, the password was correct
const userToken = jwt.sign({ id: user._id }, process.env.SECRET_KEY);
// Set the maxAge property of the cookie to 24 hours (in seconds)
res.cookie("usertoken", userToken, {
httpOnly: true,
maxAge: 24 * 60 * 60, // 24 hours in seconds
}).json({
msg: "You have successfully logged in.",
userInfo: {
id: user._id,
screenName: user.screenName,
},
});
},
// //CODING DOJO METHOD
// login: async (req, res) => {
// const user = await User.findOne({ email: req.body.email });
// if (user === null) {
// // email not found in users collection
// return res
// .sendStatus(400)
// .json({ message: "Invalid email address" });
// }
// // if we made it this far, we found a user with this email address
// // let's compare the supplied password to the hashed password in the database
// const correctPassword = await bcrypt.compare(
// req.body.password,
// user.password
// );
// if (!correctPassword) {
// // password wasn't a match!
// return res.sendStatus(400).json({ message: "Invalid password" });
// }
// // if we made it this far, the password was correct
// const userToken = jwt.sign({ id: user._id }, process.env.SECRET_KEY);
// console.log("userToken", userToken);
// console.log(
// "Yay! You have successfully signed in. Here's your usertoken: ",
// userToken,
// "User's information: ",
// req.body
// );
// // note that the response object allows chained calls to cookie and json
// res.cookie("usertoken", userToken, {
// httpOnly: true,
// // maxAge: maxAge * 1000
// // sameSite:'none'
// }).json({
// msg: "You have successfully logged in.",
// userInfo: {
// id: user._id,
// screenName: user.screenName,
// },
// });
// },
logout: (req, res) => {
// localStorage.removeItem('userDetails');
localStorage.removeItem("usertoken", userToken);
res.clearCookie("usertoken");
res.sendStatus(200).json({ message: "You have logged out!" });
},
};
UserContext.js
import {useState, createContext} from 'react';
import io from 'socket.io-client';
const UserContext = createContext();
const UserProvider = ({children}) => {
const [user, setUser] = useState({
id: 0,
screenName: "",
// room: ""
})
const [socket] = useState(() => io(":8000"))
return (
<UserContext.Provider value={{user, setUser, socket}}>
{children}
</UserContext.Provider>
)
}
export {UserProvider, UserContext}
server.js
const express = require('express');
const app = express();
const cors = require('cors')
const cookieParser = require('cookie-parser');
const dotenv = require('dotenv');
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
require('dotenv').config();
const myFirstSecret = process.env.FIRST_SECRET_KEY;
const http = require('http');
const port = 8000;
const server = app.listen(port, () => console.log("Listening on port", port));
const socketio = require('socket.io')
require('./config/mongoose.config')
app.use(cors({credentials: true, origin: 'http://localhost:3000'}));
app.use(express.json());
app.use(cookieParser());
app.use(express.urlencoded({ extended: true }));
require("./routes/awayMessage.routes")(app);
const UserRoutes = require('./routes/user.routes')
UserRoutes(app);
const io = socketio(server,{
cors: {
origin: "http://localhost:3000",
methods: ["GET", "POST"],
allowedHeaders: ['*'],
credentials: true
}
})
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
console.log(JSON.stringify(socketio))
io.on("connection", (socket) => {
console.log(" server io ...on")
console.log("Socket:", socket.id, "connected to the server");
console.log(`Message sent from ${socket.id}: ${socket}`);
// console.log("Is io on from server printing data?", data);
socket.on("send_message", (data) => {
io.emit("message_received", data)
console.log("io:", io);
console.log("emit:", emit);
})
// socket.on("join_room", (data) => {
// console.log("Joined room:", data);
// socket.join(data)
// })
socket.on("private_message", (data) => {
console.log(data);
// io.to(data.room).emit("private_message_response", data) //try this out later to add rooms
io.emit("private_message_response", data)
})
})
jwt.config.js
const jwt = require("jsonwebtoken");
secret="secret";
module.exports.secret = secret;
module.exports.authenticate = (req, res, next) => {
jwt.verify(req.cookies.usertoken, secret, (err, payload) => {
if (err) {
res.status(401).json({verified: false});
} else {
next();
}
});
}
我曾尝试将我的令牌存储到本地存储中,但我不确定我是否做对了,因为我在尝试时显然会破坏东西。 :(