简体   繁体   English

Express.js API w/ Next.js:csurf 实现

[英]Express.js API w/ Next.js: csurf implementation

Summary:概括:

I have a complete web app built with a few separate apps:我有一个完整的 web 应用程序,其中包含几个单独的应用程序:

  1. A next.js customer facing app and next.js 面向客户的应用程序和
  2. express.js web api. express.js web api。
  3. Oh and I'm using nginx as a reverse proxy to serve these both up, not sure if that is interfering but it seems that it is not interfering to me.哦,我正在使用 nginx 作为反向代理来为这两者提供服务,不确定这是否会干扰,但似乎它不会干扰我。

Everything is working very well as expected except for one thing: the gosh darn csurf implementation.除了一件事:gosh darn csurf 实现之外,一切都按预期工作得很好。 I cannot get it to work and have tried and tried.我无法让它工作并且已经尝试过。 So, I'm here for help.所以,我在这里寻求帮助。

About the apps:关于应用程序:

The next.js app renders everything customer facing. next.js 应用程序呈现面向客户的一切。 It has a custom server which doesn't do more than use helmet and a "get-user" request to my express.js web api to populate req.user and respond to my next.js app with a "user" object to render private routes. It has a custom server which doesn't do more than use helmet and a "get-user" request to my express.js web api to populate req.user and respond to my next.js app with a "user" object to render private routes .

The express.js web api manages user sessions (which is working great so far btw) over http only secure cookies set to the next.js headers and the next.js client includes these for requests to the express.js web api. The express.js web api manages user sessions (which is working great so far btw) over http only secure cookies set to the next.js headers and the next.js client includes these for requests to the express.js web api.

The problem:问题:

Everything works great but when I try to use the npm module name "csurf" in my express.js web api to set a csrf cookie for my next.js customer facing app, I cannot get this to work. Everything works great but when I try to use the npm module name "csurf" in my express.js web api to set a csrf cookie for my next.js customer facing app, I cannot get this to work. I'm successfully setting the csrf header and getting that value and I use redux to set it in the store.我已成功设置 csrf header 并获得该值,我使用 redux 在商店中设置它。 Then, when I try to get the csrftoken and apply it to a client request, that request is denied.然后,当我尝试获取 csrftoken 并将其应用于客户端请求时,该请求被拒绝。

Here are brief code implementations:以下是简要的代码实现:

  • Express.js web api, the csurf imp (csurf imp commented out, since it doesn't work, was trying to use on all api routes) Express.js web api,csurf imp(csurf imp 注释掉,因为它不起作用,试图在所有 api 路线上使用)

   import './env';
   import express from 'express';
   import csrf from 'csurf';
   import cors from 'cors';
   import morgan from 'morgan';
   import cookieParser from 'cookie-parser';
   import bodyParser from 'body-parser';
   import helmet from 'helmet';
   import redis from 'redis';
   import connectRedis from 'connect-redis';
   import session from 'express-session';

   import * as configs from '../config';

   import authRouter from './routes/authentication';
   import userRouter from './routes/user';
   import { setupLocalAuth } from './middleware/auth.middleware';

   const RedisStore = connectRedis(session);
   const client = redis.createClient({ host: configs.REDIS_CLIENT_HOST });

   const port = process.env.PORT || 5000;

   const app = express();
   app.use(cors({ origin: configs.CORS_ORIGIN, credentials: true }));
   if (configs.IS_DEV) {
      app.use(morgan('dev'));
   }
   app.use(helmet());
   app.use(cookieParser());
   app.use(bodyParser.json({ limit: '50mb' }));
   app.use(bodyParser.urlencoded({ extended: true }));
   app.use(cookieParser());
   app.use(
      session({
        name: configs.SESSION_NAME,
        secret: configs.SESSION_SECRET,
        store: new RedisStore({ client }),
        saveUninitialized: false,
        resave: false,
        proxy: configs.IS_DEV ? false : true,
        cookie: {
          domain: configs.SESSION_COOKIE_DOMAIN,
          httpOnly: true,
          secure: configs.SESSION_SECURE,
          maxAge: 14 * 24 * 60 * 60 * 1000, // 14 days
        },
      }),
    );

    /// /////////////////////////////////////////////////////////////////////////////////////////////
    //
    //
    /// /////////////////////////////////////////////////////////////////////////////////////////////
    // app.use(csrf({ cookie: true }));
    // app.use(function(req, res, next) {
    //   const token = req.csrfToken();
    //   res.cookie('XSRF-TOKEN', token);
    //   // res.locals._csrf = token;
    //   // res.locals.csrfToken = token;
    //   next();
    // });

    if (!configs.IS_DEV) {
      app.set('trust proxy', 1);
    }

    setupLocalAuth(app);
    app.use('/api/auth', authRouter);
    app.use('/api/user', userRouter);
    app.use('/api/facility', facilityRouter);
    app.use('/api/team', teamRouter);
    app.use('/api/issues', issueRouter);
    app.use('/api/forge', forgeRouter);

    // error handlers
    // development error handler
    // will print stacktrace
    if (process.env.NODE_ENV !== 'test') {
      app.use((err: any, req: express.Request, res: express.Response, next: express.NextFunction) => {
        res.status(err.status || 500);
        res.json({
          message: err.message,
          error: err,
        });
      });
    }

    // production error handler
    // no stacktraces leaked to user
    if (process.env.NODE_ENV === 'production') {
      app.use((err: any, req: express.Request, res: express.Response, next: express.NextFunction) => {
        res.status(err.status || 500);
        res.json({
          message: err.message,
          error: {},
        });
      });
    }

    app.listen(port, () => {
      console.log(`API: Listening on port: ${port}`);
    });

Then, on the Next.js side:然后,在 Next.js 端:

All I do is collect the csrf tokens and put them in my redux store for api requests.我所做的就是收集 csrf 令牌并将它们放入我的 redux 存储中,用于 api 请求。 One thing though: when I console log the csrf tokens from the express.js web api and what I've received on the next.js side, they never match.不过有一件事:当我从 express.js web api 和我在 next.js 端收到的内容控制台记录 csrf 令牌时,它们永远不会匹配。 So I think that is the culprit but the dang thang doesn't make sense to me.所以我认为这是罪魁祸首,但当当对我来说没有意义。 I'm making a mistake somewhere.我在某处犯了错误。

One big question remains, do I even need to do this for SPA approach?一个大问题仍然存在,我什至需要为 SPA 方法执行此操作吗? I set up a Django app in like 4 days and this was sooooo easy as the html was rendered traditionally on the server.我在 4 天内设置了一个 Django 应用程序,这非常简单,因为 html 传统上是在服务器上呈现的。

Thanks a bunch!非常感谢!

I figured it out.我想到了。

What I needed to do was to grab the " res.cookie('XSRF-TOKEN', token);"我需要做的是获取“ res.cookie('XSRF-TOKEN', token);” cookie in my front-end js app and put that in my req.body as _csrf. cookie 在我的前端 js 应用程序中,并将其作为 _csrf 放在我的 req.body 中。 Now it works!现在它起作用了!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM