使用带有React.js前端

时间:2017-09-27 09:36:28

标签: node.js reactjs authentication cookies passport.js

在身份验证方面,我是一个新手。我正在尝试将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的效果如何,因为他的前端似乎没有发回任何令牌/数据供后端检查,而且我(理所当然有限)的理解这就是它应该如何。

知道我做错了吗?

1 个答案:

答案 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);