在带有React.js前端的Node.js上使用Passport.js进行身份验证
说到认证,我完全是个新手。我正在尝试将科尔特·斯蒂尔(Colt Steele)使用的方法作为我项目的一部分 Colt使用Node.js+Express.js+MongoDB,在ejs中进行服务器端渲染。对于用户身份验证,他使用Passport.js 我使用Node.js+Express.js+MongoDB,并使用React.js进行客户端渲染。我也使用React路由器。我还尝试使用Passport对用户进行身份验证 我的问题是,虽然我可以成功登录,但仍然无法访问登录墙后面的任何内容。当我向服务器请求某个路由以检查用户是否经过身份验证时,答案总是false 这是我的身份验证码在带有React.js前端的Node.js上使用Passport.js进行身份验证,node.js,reactjs,authentication,cookies,passport.js,Node.js,Reactjs,Authentication,Cookies,Passport.js,说到认证,我完全是个新手。我正在尝试将科尔特·斯蒂尔(Colt Steele)使用的方法作为我项目的一部分 Colt使用Node.js+Express.js+MongoDB,在ejs中进行服务器端渲染。对于用户身份验证,他使用Passport.js 我使用Node.js+Express.js+MongoDB,并使用React.js进行客户端渲染。我也使用React路由器。我还尝试使用Passport对用户进行身份验证 我的问题是,虽然我可以成功登录,但仍然无法访问登录墙后面的任何内容。当我向服务
const express = require("express"),
server = express(),
path = require("path"),
mongoose = require("mongoose"),
User = require("./models/User"),
bodyParser = require("body-parser"),
passport = require("passport"),
localStrategy = require("passport-local"),
passportLocalMongoose = require("passport-local-mongoose"),
expressSession = require("express-session");
mongoose.connect("mongodb://localhost/diary");
server.use(
bodyParser.urlencoded({
extended: true
})
);
//Auth
server.use(
expressSession({
secret: "This is pretty damn weird.",
resave: false,
saveUninitialized: false
})
);
server.use(passport.initialize());
server.use(passport.session());
passport.use(new localStrategy(User.authenticate()));
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
// Auth login
server.post("/login", function(request, response) {
passport.authenticate("local", function(err, user, info) {
if (err) {
return console.log(err);
}
if (!user) {
return response.send(false);
}
request.logIn(user, function(err) {
if (err) {
return console.log(err);
}
checkLogIn(request, response);
return response.send(true);
});
})(request, response);
});
//Auth checkLogIn
function checkLogIn(request, response) {
if (request.isAuthenticated()) {
return console.log("authenticated");
} else {
return console.log("not authenticated");
}
}
因为我使用的是客户端渲染,所以无法使用response.redirect将用户重定向到任何地方。这就是为什么我使用response.send(true)(或false):我使用它们作为标志来告诉React应用程序该做什么
上面的代码与Colt的几乎相同:他将expressSession的配置保持在最低限度,并且似乎没有定义自己的本地策略或(反)序列化函数。在我发现的几个教程中,每个人似乎都这么做了,但柯尔特没有,他的应用程序运行得很好。他也不使用任何MongoStore,其他很多人似乎都这么做
正如您所看到的,我有一个checkLogIn函数,名为right after request.logIn,它只记录console.log用户是否登录。登录后,屏幕上会显示true,即登录确实成功
此时我应该登录,但如果我试图从浏览器访问受保护的分区,我会被告知我没有登录。例如,我成功地以假用户Elmo的身份登录,然后尝试访问/Elmo/diary。这将带我到一个React组件,该组件在特定路由上查询服务器,如下所示:
//Find all entries of a given user.
router.get("/entries/:userURL", isLoggedIn, (request, response) => {
console.log("get entries");
User.findOne(
{ customURL: request.params.userURL },
{ entryIDs: 1 },
(err, data) => {
//Get the actual entries.
Entry.find({ _id: { $in: data.entryIDs } }, (err, entries) => {
if (err) {
console.log(err);
} else {
response.send(entries);
}
});
}
);
});
如您所见,我使用的是isLoggedIn中间件,如下所示:
//Auth isLoggedIn
function isLoggedIn(request, response, next) {
console.log(request);
if (request.isAuthenticated()) {
console.log("logged in");
return next();
}
console.log("not logged in");
return (function() {
response.send(false);
})();
}
因此,如果我以Elmo身份登录,上面的路由应该返回数据。但是,无论我是否登录,中间件都会返回false
我检查了运行应用程序的localhost的cookie,其中只有一个具有令牌值(s%3Ak0SZJ97eJkPjqjE6jC-azn7y3ztK2UMw.fYOfM9324JUIeUDGvh26swEWwMf3j3HDUmh9WubNF%2B8),因此我猜Passport正在成功创建会话并将其存储在cookie中
老实说,我也不确定这个系统是如何为Colt工作的,因为他的前端似乎没有返回任何令牌/数据供后端检查,而我(承认有限)的理解是,这是应该的
知道我做错了什么吗?当你说“登录墙”时,我假设你想进入受保护的路由/组件。我相信您需要一个带有react路由器的受保护路由,如下所示:
//Placed near your other react router routes, pass the logged in state to this route
<PrivateRoute path="/dashboard" component={Dashboard} loggedIn={loggedIn} />
//If auth'd, redirect to the component you want, if not then redirect to login
const PrivateRoute = ({ component: Component, ...rest, loggedIn }) => (
<Route
{...rest}
render={props => (
loggedIn ? (
<Component {...props} />
) : (
<Redirect to={{
pathname: '/login',
state: { from: props.location },
}}
/>
)
)}
/>
);
对于客户端路由,您使用的是react-router还是express?@Dream\u Cap react-router。登录时,loggedIn的值如何传递到所有路由?我更新了答案,以包含有关该问题的更多信息。此答案是否有帮助?我仍在努力找出答案。我现在正在学习一个Udemy课程,说react根本不需要参与,因为浏览器会自动将身份验证cookie附加到每个http请求。实际上,我并不真正需要受保护的路由,只需要身份验证来决定是否可以向用户显示某些数据。对不起,我的措辞有点混乱。无论如何,谢谢你的帮助!
const AllRoutes = ({ loggedIn }) => (
<BrowserRouter history={history}>
<div>
<PrivateRoute path="/dashboard" component={Dashboard} loggedIn={loggedIn} />
//other routes
</div>
</BrowserRouter>
);
//import connect for connecting the component into redux's store(state)
import { connect } from 'react-redux';
//map redux's store to props so the component can access it (this is how loggedIn can get passed in)
const mapStateToProps = state => ({
loggedIn: state.signup.loggedIn,
});
//wraps the component in Redux's store(state)
export default connect(mapStateToProps, null)(AllRoutes);