繁体   English   中英

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

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

概括:

我有一个完整的 web 应用程序,其中包含几个单独的应用程序:

  1. next.js 面向客户的应用程序和
  2. express.js web api。
  3. 哦,我正在使用 nginx 作为反向代理来为这两者提供服务,不确定这是否会干扰,但似乎它不会干扰我。

除了一件事:gosh darn csurf 实现之外,一切都按预期工作得很好。 我无法让它工作并且已经尝试过。 所以,我在这里寻求帮助。

关于应用程序:

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 .

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.

问题:

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. 我已成功设置 csrf header 并获得该值,我使用 redux 在商店中设置它。 然后,当我尝试获取 csrftoken 并将其应用于客户端请求时,该请求被拒绝。

以下是简要的代码实现:

  • 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}`);
    });

然后,在 Next.js 端:

我所做的就是收集 csrf 令牌并将它们放入我的 redux 存储中,用于 api 请求。 不过有一件事:当我从 express.js web api 和我在 next.js 端收到的内容控制台记录 csrf 令牌时,它们永远不会匹配。 所以我认为这是罪魁祸首,但当当对我来说没有意义。 我在某处犯了错误。

一个大问题仍然存在,我什至需要为 SPA 方法执行此操作吗? 我在 4 天内设置了一个 Django 应用程序,这非常简单,因为 html 传统上是在服务器上呈现的。

非常感谢!

我想到了。

我需要做的是获取“ res.cookie('XSRF-TOKEN', token);” cookie 在我的前端 js 应用程序中,并将其作为 _csrf 放在我的 req.body 中。 现在它起作用了!

暂无
暂无

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

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