当前位置: 首页 > 知识库问答 >
问题:

发布帆/节点。js到孔格里盖特

沃皓轩
2023-03-14

所以,我的基于帆的MMORTS游戏终于要去Kongregate了。几乎没有障碍,比如连接WebSocket,但现在已经解决了。最后一个障碍可能是保持经过身份验证的会话。我到处都在使用框架,我不知道身份验证会话在幕后是如何工作的<主要问题可能是CSRF或CORS<我用的是帆v1。所以,我从HTML开始,然后上传到kongregate。我举一个最简单的例子:

<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta charset="utf-8">

    <script src="jquery.js"></script>
    <script src='https://cdn1.kongregate.com/javascripts/kongregate_api.js'></script>

    <script src="sails.io.js"
      autoConnect="false"
      environment="production"
      headers='{ "x-csrf-token": "" }'
    ></script>

    <script type="text/javascript">
      io.sails.url = 'https://my-secret-game.com'; // or where you want
    </script>

  </head>
  <script src="main.js"></script>
</html>

这是main.js我也上传到Kongregate了

kongregateAPI.loadAPI(function(){
  window.kongregate = kongregateAPI.getAPI();
  var username = kongregate.services.getUsername();
  var id = kongregate.services.getUserId();
  var token = kongregate.services.getGameAuthToken();

  $.get("https://my-secret-game.com/csrfToken", function (data, jwres) {

    var params = {
      username: username,
      id: id,
      token: token,
      _csrf: data._csrf
    };

    $.post("https://my-secret-game.com/kong", params, function(data, jwr, xhr){

      // cant set the cookie - because of chrome. this doesnt work
      document.cookie = document.cookie + ';authenticated=true;sails.sid=' + data.id;

      $.get("https://my-secret-game.com/csrfToken", function (data, jwres) {
        var msg = {
          testing_authentication: true,
          _csrf: data._csrf
        };
        $.post("https://my-secret-game.com/test", msg, function(data, status){
          // getting the 403 Forbidden, CSRF mismatch. trying to access 
          // the play/test route, which is protected by sessionAUTH
          console.log('data.response', data.response)
        });

      });
    });
  });
});

问题是,每当我试图用sessionAUTH发布我的Sails后端时,我都会被禁止403。我也不能设置饼干-可能是因为Chrome。我能做什么?当我获得CSRF令牌时,在下一个请求中,我的Sails应用程序会响应CSRF不匹配。这就错了。

这是我的Sails后端服务器上的控制器

module.exports = {
  kong: function (req, res, next) {
    var url = 'https://api.kongregate.com/api/authenticate.json';
    var kong_api_key = 'my-secred-api-key';
    var params = req.allParams();
    var request = require('request');

    var req_form = {
      "api_key": kong_api_key,
      "user_id": params.id,
      "game_auth_token": params.token
    };

    request({
        url: url,
        method: "POST",
        json: true,
        body: req_form,
        timeout: 5000
    }, function (err, response, body){
       if(err) { console.log(err, 'ERR43'); return res.ok(); }
       else {
        if(!response.body.success) {
          console.log('unsuccessful login from kongregate')
          return res.ok();
        }

        // trying to use a existing user and authenticate to it
        User.find({username: 'admin-user'}).exec(function(err, users) {
          var user = users[0];
          req.session.authenticated = true;
          req.session.user = { id: user.id };

          // trying to send session_id, so that i could hold it on kongregates cookies as `sid`
          return res.send({ user: user, id: req.session.id });

        });
       }
    });
  },

请您帮助修复我的应用程序的身份验证和CSRF?

如果需要有关我的配置的更多信息,这是配置/会话。js

var prefixes = 'dev';

module.exports.session = {
  secret: 'my-secret',

  cookie: {
     secure: false
  },

  adapter: 'redis',

  host: 'localhost',
  port: 6379,
  ttl: 3000000,
  db: 0,
  prefix: prefixes + 'sess:',
};

配置/策略。js

module.exports.policies = {
  user: {
    'new':    'flash',
    'create': 'flash',
    'edit':   'rightUser',
    'update': 'rightUser',
    '*':      'sessionAuth'
  },
  play: {
    '*': 'sessionAuth'
  }
};

API/政策/会话Auth.js

module.exports = function(req, res, next) {
  if (req.session.authenticated) {
    return next();
  } else {
    var requireLoginErr = [
      { name: 'requireLogin', message: 'You must be signed in' }
    ];
    req.session.flash = {
      err: requireLoginErr
    };
    res.redirect('/');
    return;
  }
};

配置/安全。js

module.exports.security = {
    csrf: true,
  cors: {
    allowRequestMethods: 'GET,PUT,POST,OPTIONS,HEAD',
    allowRequestHeaders: 'content-type,Access-Token',
    allowResponseHeaders: '*',
    allRoutes: true,
    allowOrigins: '*',
    allowCredentials: false,
  },
};

共有1个答案

冯阳成
2023-03-14

好吧,因为我没有答案(很明显,这个问题很糟糕),所以我用我自己解决的答案来回答,这样下次我就可以阅读我自己了。不确定它有多好,但至少它是有效的。

Sails CORS采用的是Express。js并允许将套接字连接到kongregate,前提是我允许它在配置中使用。但它不允许通过发送帆以正常方式进行身份验证。通过Cookie的sid(身份验证令牌)。

由于安全原因,Chrome不允许将带有javascript的cookie(我在Kongregate上没有后端)设置为标题。因此,如果我不能发送带有标题的cookie,SAIL就不能以正常的方式对请求进行身份验证。即使我允许CORS接受“cookie”头,浏览器也不允许用javascript设置cookie头。

我可以制作一些独特的标题,比如“身份验证”,并设置航向。在这里,扩展Sails的一些核心功能,以获取这个新的头,而不是cookie头。但问题是——在背靠的帆上,我无法获得所有这些帆。sid并将其发送到我的外部前端。。它是在哪里创建的?我怎样才能拿到帆。希德在帆船上?不确定——不能用谷歌搜索。

所以,我只是以一种最简单的方式进行了身份验证——在帐户登录/注册时,我只是自己创建了一个会话密钥——使用bcrypt哈希user_id secret_token(取自sails config secrets)。并发送到前端{user_id:'abcd',secret_token:'a2dw412515…}

我在Sails中制定了对每个POST/GET请求进行身份验证的策略-获取请求的session_id和user_id,并比较使用bcrypt,session_id是否与加密user_idsecret_token相同。我希望它足够安全。

所以,它成功了。我只需要禁用CSRF。也许有一天我会再次实现它,我只需要以我的方式编写它,而不是留下默认值。

工作守则:

前沿

// you upload this HTML file to kongregate
// also you upload additionally ZIP named "kongregate_uploaded_folder" with libraries like sails.io, jquery

<!DOCTYPE html>
<html>
  <head>
    <script src="kongregate_uploaded_folder/jquery.js"></script>
    <script src='https://cdn1.kongregate.com/javascripts/kongregate_api.js'></script>
    <script src="kongregate_uploaded_folder/sails.io.js"
      autoConnect="false"
      environment="production"
    ></script>
  </head>

  <body style="padding:0; margin:0; overflow:hidden;">

  <div style="position:absolute; margin: 0px; padding: 0px;">
    <canvas id="main_canvas" style="position:absolute;" width="640" height="480" >Best initial resolution to have in Kongregate</canvas>
  </div>

  <script>
    // the first thing happends - you try to connect your frontend with Kongregate
    kongregateAPI.loadAPI(function(){
      window.kongregate = kongregateAPI.getAPI();

      if(!kongregate.services.isGuest()) {
        var params = {
          username: kongregate.services.getUsername(),
          id: kongregate.services.getUserId(),
          token: kongregate.services.getGameAuthToken(),
        };

        // call your backend to create a new session and give you session_id
        $.post("https://your_game_server.com/kong", params, function(data, jwr, xhr){
          var kong_session_id = data.kong_session_id;
          var kong_user_id = data.kong_user_id;
          var user = data.user;

          // connect your sockets with the server in this way
          io.socket = io.sails.connect("https://your_game_server.com", { useCORSRouteToGetCookie: false, reconnection: true });

          // subscribe to the global sockets channel. You have to make this route and code, but here is a example
          io.socket.get('/subscribe', { kong_session_id: kong_session_id, kong_user_id: kong_user_id }, function(data, jwr){
            if (jwr.statusCode == 200){
              io.socket.on(data.room, function(event){
                // on any server-side event, you will get this "event" message. At this part you decide what to do with this data
                incoming_socket_event(event); // i wont write this function
              });
              // your game continues here:
              $.get("https://your_game_server.com/player_data?kong_session_id=" + kong_session_id + "&kong_user_id=" + kong_user_id, params, function(data, jwr, xhr){
              // you will get authenticated "current_user"
            }
          });

        })
      }
    });
  </script>
</html>

后端

// SAILS BACKEND:   home_controller.js
module.exports = {
  kong: function (req, res, next) {
    // player has already opened your game in kongregate.com and frontend requests this endpoint POST /kong { id: 84165456, token: 'as54..' }
    // you need to create a new session for this player, or register this player. This is your own session creation, since default sails session wont work with external website frontend.
    var req_params = {
      url: "https://api.kongregate.com/api/authenticate.json", // default URL to validate kongregate user
      method: "POST",
      json: true,
      body: { 
        api_key: 'gg000g00-c000-4c00-0000-c00000f2de8', // kongregate will provide this api-key for server-side connection (this one has some letters replaced)
        user_id: 84165456, // when frontend requests POST /kong { id=84165456 } , this 84165456 is provided by kongregate in the frontend
        game_auth_token: "as54a45asd45fs4aa54sf" // when frontend requests POST /kong { token = 'as54..' }, this is provided by kongregate in the frontend
      },
      timeout: 20000
    }

    // request kongregate that this is the real player and you will get a username
    request(req_params, function (err, response, body){
      var response_params = response.body; // response from kongregate API

      // search for user with this kongregate_id inside your database, maybe he is already registered, and you need just to create a new session.
      User.find({ kongregate_id: response_params.user_id }).exec(function(err, usr) {
        var user = usr[0]

        // if player already has an account inside your online game
        if(user) {
          // create new session for this user.
          require('bcryptjs').hash("your_own_random_secret_key" + user.id, 10, function sessionCreated(err, kong_session_id) {

            // send this info to frontend, that this player has been connected to kongregate
            return res.send({ 
              user: user, 
              kong_session_id: kong_session_id, 
              kong_user_id: user.id 
            });
          });            

        //if this is new user, you need to register him
        } else { 
          var allowedParams = {
            username: response_params.username, // kongregate will give you this player username
            email: 'you_have_no_email@kong.com', // kongregate does not provide email
            password: 'no_password_from_kongregate',
            kongregate_id: response_params.user_id // kongregate will give you this player id
          };

          User.create(allowedParams, function(err, new_user) {
            // create new session for this user.
            require('bcryptjs').hash("your_own_random_secret_key" + new_user.id, 10, function sessionCreated(err, kong_session_id) {

              // send this info to frontend, that this player has been connected to kongregate
              return res.send({ 
                user: new_user, 
                kong_session_id: kong_session_id, 
                kong_user_id: new_user.id 
              });
            }); 
          });
        }
      });
    });
  },
};

路线

    // config/routes.js
    module.exports.routes = {
      'GET /player_data': 'PlayController.player_data',
      'GET /subscribe': 'PlayController.subscribe',
      'POST /kong': {
         action: 'home/kong',
         csrf: false // kongregate is a external website and you will get CORS error without this
      },
    };

安全

// config/security.js
module.exports.security = {
    csrf: false,
  cors: {
    allowOrigins: ['https://game292123.konggames.com'], // your game ID will be another, but in this style
    allowRequestMethods: 'GET,POST',
    allowRequestHeaders: 'Content-Type',
    allowResponseHeaders: '',
    allRoutes: true,
    allowCredentials: false,
  },
};

插座

// config/sockets.js
module.exports.sockets = {
  grant3rdPartyCookie: true,
  transports: ["websocket"],
  beforeConnect: function(handshake, cb) { return cb(null, true); },
};

配置策略

// /config/policies.js
module.exports.policies = {
  play: {'*': 'sessionAuth'},
};

API政策

// /app/sessionAuth.js
module.exports = function(req, res, next) {
  var params = req.allParams();
  // your own session handling way to get the user from session token
  require('bcryptjs').compare("your_own_random_secret_key" + params.kong_user_id, params.kong_session_id, function(err, valid) {
    req.session.authenticated = true;
    req.session.user_id = params.kong_user_id;
    return next();
  });
};

控制器

// /api/controllers/PlayController.js
module.exports = {
    player_data: async function (req, res, next) {
        var users = await User.find(req.session.user_id);
        return res.send({ current_user: users[0] });
    },
    subscribe: async function (req, res, next) {
      var users = await User.find(req.session.user_id);
      var roomName = String(users[0].id);
      sails.sockets.join(req.socket, roomName);
      res.json({ room: roomName });
    },
}
 类似资料:
  • 我正在使用Node开发一个应用程序。js和帆。 我将像这样运行:同时运行同一应用程序的20个实例,所有实例都将使用本地MongoDB存储模型数据。 我的问题是这样开始的:只有前7或8个启动的应用程序正在启动,其他应用程序由于无法连接到数据库而失败。 好吧,我进行了一些搜索,发现我必须增加连接数,但让我觉得有问题的是:每个启动的应用程序都在创建大约35个连接! 所以,当发布6或8个应用程序时,他们需

  • 我正在编写一个简单的node js应用程序。 索引。js 预期:请求正文应从服务器注销 实际: 应用程序。js日志 指数js日志 有人能帮我理解我在这里错过了什么吗?非常感谢。关于这个话题,答案很少。

  • 我有一个文件Image.TIFF有3页。我想在FS中保存每一页在单独的文件中。我尝试使用一个尖锐的库来提取每一页并保存它。我从元数据的高度,宽度,和页数,所以我可以计算位置的作物面积。但是当我检查高度时,我发现我只得到了单个页面的高度,而不是所有页面的总高度(这是我希望得到的),所以我只得到了第一页的顶部部分。不酷。有什么想法如何裁剪每一页分开吗?或者其他解决我问题的方法。谢谢! }

  • 问题内容: 我有一个通过node.js运行的JS文件,因此通常我会打开一个终端窗口并输入类似内容,然后它会整天运行;好玩 然后,当我想重新启动它时,我按下Ctrl-c,然后退出。然后,我可以再次运行命令。 现在,我想做的是能够通过网页执行此操作,以便我的用户可以运行特定的JS文件,也可以“重新引导”它们。 因此有两个问题: 有可能,如果可以,我如何开始? 它安全吗?如果不安全,可以安全吗? 基于s

  • 我有这个问题: 我正在使用javaFX和场景生成器(2.0),我已经将scrollPane放入我的窗口,而窗口又包含anchorPane。当我启动我的应用程序时,一切正常,但是当我以编程/动态方式将节点添加到anchorPane时,出于某种原因,我的应用程序的整个布局变得奇怪/错误。基本上,所有内容都保持在prefWidth和prefHeight中,并且在调整应用程序窗口大小时不会调整大小,而在将

  • 我在运行程序时遇到此错误 错误: ReferenceError:未在C:\Users\H00422000\desktop\newsletter signup\app中定义选项。第三层的js:39:33。在路由的下一个(C:\Users\H00422000\desktop\newsletter signup\node\u modules\express\lib\router\layer.js:95: