在身份验证方面,我是一个新手。我正在尝试将Colt Steele使用的方法作为他web developer's bootcamp course的一部分用于我的项目。
Colt使用Node.js + Express.js + MongoDB,在ejs中使用服务器端渲染。对于用户身份验证,他使用Passport.js。
我正在使用Node.js + Express.js + MongoDB与React.js进行客户端渲染。我也使用React Router。我也试图使用Passport来验证用户身份。
我的问题是,虽然我可以成功登录,但我仍然无法访问登录墙后面的任何内容。当我向服务器发出请求以检查用户是否经过身份验证的路由时,答案始终为false。
这是我的身份验证码。
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的配置保持在最低限度,并且似乎没有定义他自己的本地策略或(de-)序列化功能。在我发现的几个教程中,每个人似乎都这样做,但Colt没有,而且他的应用程序工作得很好。他也没有使用任何MongoStore,很多其他人似乎都这样做。
正如你所看到的,我在request.logIn之后调用了一个checkLogIn函数,只是console.logs用户是否登录。登录后,它会在屏幕上显示true,即登录确实成功
此时我应该登录,但如果我尝试从浏览器访问受保护的部分,我会被告知我没有登录。例如,我成功登录为虚假用户Elmo,然后尝试访问/ elmo /日记。这将我带到一个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。
我检查了我的cookies for localhost,应用程序正在运行,并且只有一个,具有令牌标记值(s%3Ak0SZJ97eJkPjqjE6jC-azn7y3ztK2UMw.fYOfM9324JUIeUDGvh26swEWwMf3j3HDUmh9WubNF%2B8),所以我想Passport正在创建会话和存储它在cookie中成功。
老实说,我不确定这个系统对Colt的效果如何,因为他的前端似乎没有发回任何令牌/数据供后端检查,而且我(理所当然有限)的理解这就是它应该如何。
知道我做错了吗?
答案 0 :(得分:0)
当您说'登录墙'时,我假设您想要访问受保护的路线/组件。我相信你需要一个带有react-router的受保护路由,如下所示:
//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 },
}}
/>
)
)}
/>
);
至于让您的路由了解您是否已登录,我认为您需要将express的auth响应存储在本地React Component状态或Redux中(我最近在我的博客项目{{3}中执行此操作)它将位于您的redux存储(状态)中,因为您可以在需要时从多个视图/组件访问它。例如,可以在多个视图中检索登录状态。
以下是路线的示例:
const AllRoutes = ({ loggedIn }) => (
<BrowserRouter history={history}>
<div>
<PrivateRoute path="/dashboard" component={Dashboard} loggedIn={loggedIn} />
//other routes
</div>
</BrowserRouter>
);
以下是Redux部分将loggedIn传递给allRoutes的内容:
//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);