我正在将 Express 和节点用于 React 应用程序,但谷歌身份验证不起作用。我正在使用快速会话。当我登录到我的 React 应用程序时,它可以识别 req.session.user,但是当我注销或使用路由获取用户时,它说 req.session.user 未定义
这就是我的 app.js 的样子:
import express from "express";
import api from "./routes/api.js";
import path from "path";
import { OAuth2Client } from 'google-auth-library';
import dotenv from 'dotenv';
import session from 'express-session';
dotenv.config();
const client = new OAuth2Client(process.env.REACT_APP_GOOGLE_CLIENT_ID);
const users = new Array();
let app = express();
let sessionHandler = session({
//used to sign the session id, maxAge is the time in ms
secret: process.env.SECRET,
name: 'id',
saveUninitialized: false,
resave: false,
cookie: {
maxAge: null,
secure: true,
httpOnly: true,
sameSite: 'strict'
}
});
app.use(express.static("client/build"))
app.use(express.json());
app.use("/api", api);
function sessionMiddleWare (req, res, next) {sessionHandler(req, res, next);}
app.post("/auth", sessionMiddleWare, async (req, res) =\> {
//TODO: should validate that the token was sent first
const { token } = req.body;
const ticket = await client.verifyIdToken({
idToken: token,
audience: process.env.REACT_APP_GOOGLE_CLIENT_ID
});
if (!ticket) {
return res.sendStatus(401);
}
const { name, email, picture } = ticket.getPayload();
//TODO: may want to update and insert the user's name, email and picture in the db.
//For now I will be using an array, as a mock data that is on top of the app.js
const user = { "name": name, "email": email, "picture": picture };
const existsAlready = users.findIndex(elem =\> elem.email === email);
if (existsAlready \< 0) {
//insert
users.push(user);
} else {
//update
users\[existsAlready\] = user;
}
//TODO: create a session cookie send it back to the client
req.session.regenerate(function (err) {
if (err) {
//server error, couldn't create the session
return res.sendStatus(500);
}
//store the user's info in the session
req.session.user = user;
res.json({ user: user });
});
});
function isAuthenticated(req, res, next) {
console.log(req.session.user);
if (!req.session.user) {
//unauthorized
return res.sendStatus(401);
}
next();
}
app.get("/protected", sessionMiddleWare, isAuthenticated, function (req, res) {
//would actually be doing something
res.sendStatus(200);
});
app.get("/logout", sessionMiddleWare, isAuthenticated, function (req, res) {
//destroy the session
req.session.destroy(function (err) {
//callback invoked after destroy returns
if (err) {
//server error, couldn't destroy the session
return res.sendStatus(500);
}
res.clearCookie('id');
res.sendStatus(200);
});
});
export default app;
这是前端的 App.js:
import './App.css';
import Header from "./components/Header.js";
import { useState } from 'react';
import { GoogleLogin, GoogleOAuthProvider } from '@react-oauth/google';
function App() {
const [username, setUserName] = useState("");
//handle the login
const handleLogin = async googleData =>{
const res = await fetch("/auth", {
method: "POST",
body: JSON.stringify({token: googleData.credential}),
headers: {
"Content-Type": "application/json"
}
});
// server will be replying with the info
const data = await res.json();
console.log(data);
setUserName(data.user.name);
}
//handle log out, nothing to do with google, only has to do with the
//session on the Express server
const handleLogout = async () => {
await fetch("/logout");
setUserName("");
}
//protected route callback
const protectedRoute = async () => {
const resp = await fetch("/protected");
if(resp.status === 200) {
// eslint-disable-next-line no-alert
alert("You are authorized to see this");
} else if (resp.status === 401) {
// eslint-disable-next-line no-alert
alert("You are not authorized to see this!");
} else {
// eslint-disable-next-line no-alert
alert("Something went wrong!");
}
}
return (
<div className="App">
<h2>Welcome {username ? username : "Anonymous"}</h2>
<Header/>
<GoogleOAuthProvider clientId={process.env.REACT_APP_GOOGLE_CLIENT_ID}>
{!username &&
<GoogleLogin
onSuccess={handleLogin}
onError={() =>{
console.log('Loging Failed');
}}
/> }
{username && <button onClick={handleLogout}>Logout</button>}
<button onClick={protectedRoute}>Test protected</button>
</GoogleOAuthProvider>
</div>
);
}
export default App;