Iron Router和Meteor中的服务器端路由

时间:2021-07-30 16:30:03

Forward

It seems that in Meteor, we cannot call a server side route to render a file to the page without some sort of work-around from our normal workflow, from what I've read about server side routes. I hope I'm wrong about this, and there's a simple way to achieve what I'm looking to do...

似乎在Meteor中,我们不能调用服务器端路由将文件呈现到页面,而不需要从我们正常的工作流程中解决某些问题,从我读到的有关服务器端路由的内容。我希望我对此错了,并且有一种简单的方法来实现我想要做的......

** Sorry if this is a little long, but I think in this case providing more background and context is warranted **

**对不起,如果这有点长,但我想在这种情况下提供更多的背景和背景是有道理的**

Software/Versions

I'm using the latest Iron Router 1.* and Meteor 1.* and to begin, I'm just using accounts-password.

我正在使用最新的Iron Router 1. *和Meteor 1. *并开始,我只是使用帐户密码。

Background/Context

I have an onBeforeAction that simply redirects the user to either the welcome page or home page base upon if the user is logged in or not:

我有一个onBeforeAction,根据用户是否登录,只需将用户重定向到欢迎页面或主页:

both/routes.js

Router.onBeforeAction(function () {
  if (!Meteor.user() || Meteor.loggingIn())
    this.redirect('welcome.view');
  else
    this.next();
  }
  ,{except: 'welcome.view'}
);

Router.onBeforeAction(function () {
  if (Meteor.user())
    this.redirect('home.view');
  else
    this.next();
  }
  ,{only: 'welcome.view'}
);

In the same file, both/routes.js, I have a simple server side route that renders a pdf to the screen, and if I remove the onBeforeAction code, the route works (the pdf renders to the page):

在同一个文件中,两个/ routes.js,我有一个简单的服务器端路由,将pdf呈现给屏幕,如果我删除onBeforeAction代码,路由工作(pdf呈现到页面):

Router.route('/pdf-server', function() {
  var filePath = process.env.PWD + "/server/.files/users/test.pdf";
  console.log(filePath);
  var fs = Npm.require('fs');
  var data = fs.readFileSync(filePath);
  this.response.write(data);
  this.response.end();
}, {where: 'server'});

Exception thrown on Server Route

It's beside the point, but I get an exception when I add the above server side route to the file and take the route /pdf-server, while keeping the onBeforeAction code in place.

它不是重点,但是当我将上述服务器端路由添加到文件并获取路由/ pdf-server时,我得到一个例外,同时保持onBeforeAction代码到位。

Insights into the exception can be found here: SO Question on Exception

可以在此处找到对异常的见解:SO异常问题

Solution to the Exception

The main gist of the answer in the SO Question above is "You use Meteor.user() in your Route.onBeforeAction but it has no access to this information", and when, "your browser make a GET/POST request" [Server side route?], "to the server it doesn't have any information regarding the user's authentication state."

上面的SO问题中答案的主要要点是“你在Route.onBeforeAction中使用Meteor.user(),但是它无法访问这些信息,”当你的浏览器发出GET / POST请求时“ side route?],“到服务器它没有关于用户身份验证状态的任何信息。”

The solution, according to the same SO answerer is to "find an alternative way to authenticate the user," and one way to do this is to use "cookies'".

根据相同的SO回答者的解决方案是“找到另一种验证用户的方法”,其中一种方法是使用“cookies”。

So, following up on this, I found another SO answer (by the same answerer as before), where a method to set and get the cookies is outlined here: SO Cookies technique

所以,跟进这一点,我找到了另一个SO答案(与之前一样的回答者),其中概述了设置和获取cookie的方法:SO Cookies技术

** So, to summarize, in order to allow for server side routes, it is suggested I use cookies instead of something like Meteor.userId() or this.userId. **

**因此,总而言之,为了允许服务器端路由,建议我使用cookie而不是像Meteor.userId()或this.userId这样的东西。 **

Cookie related code added

So I added the following code to my project: client/main.js

所以我将以下代码添加到我的项目中:client / main.js

Deps.autorun(function() {
    if(Accounts.loginServicesConfigured() && Meteor.userId()) {
        setCookie("meteor_userid",Meteor.userId(),30);
        setCookie("meteor_logintoken",localStorage.getItem("Meteor.loginToken"),30);
    }
}); 

In my server side route, I changed the route to this:

在我的服务器端路由中,我将路由更改为:

both/routes.js

Router.route('/pdf-server', function() {
  //Parse cookies using get_cookies function from : https://*.com/questions/3393854/get-and-set-a-single-cookie-with-node-js-http-server
  var userId = get_cookies(req)['meteor_usserid'];
  var loginToken = get_cookies(req)['meteor_logintoken'];
  var user = Meteor.users.findOne({_id:userId, "services.resume.loginTokens.token":loginToken});
  var loggedInUser = (user)?user.username : "Not logged in";

  var filePath = process.env.PWD + "/server/.files/users/test.pdf";
  console.log(filePath);
  var fs = Npm.require('fs');
  var data = fs.readFileSync(filePath);
  this.response.write(data);
  this.response.end();
}, {where: 'server'});

But this does not work as expected, the setCookie code is not valid for some reason.

但是这没有按预期工作,setCookie代码由于某种原因无效。

My Questions

Question 1: Setting/getting the cookies in the manner depicted in the SO Cookies technique doesn't seem to work for me, does this technique still work in '15?

问题1:以SO Cookies技术描述的方式设置/获取cookie对我来说似乎不起作用,这项技术是否仍然适用于'15?

Question 2: Using cookies, how do I inform the server of the authentication state based on these cookies? Or, another way, How does adding the cookie check in my server side route "inform" the server about the user? I could check for anything in this route really; I could reject any user, but somehow the server needs to "know" about the user logged in right?

问题2:使用cookie,如何根据这些cookie通知服务器认证状态?或者,另一种方式,如何在我的服务器端路由中添加cookie检查“通知”服务器有关用户的信息?我真的可以检查这条路线上的任何东西;我可以拒绝任何用户,但不知何故服务器需要“知道”用户登录的权利吗?

Question 3: Is cookies the best way to go about this, or is there a simpler way to achieve the same thing?

问题3:Cookie是最好的解决方法,还是有更简单的方法来实现同样的目标?

Side Question: I've seen a few places where middle ware is used for server side routes, for example:

方问:我看过一些中间件用于服务器端路由的地方,例如:

WebApp.connectHandlers.stack.splice(...);

WebApp.connectHandlers.use(function(...) ...);

But none of these examples had security inside, will using middle ware in this way allow me to get around my problem?

但是这些例子都没有内部安全性,以这种方式使用中间件可以让我解决我的问题吗?

1 个解决方案

#1


8  

Your server-side routes are running the global onBeforeAction code (it's defined in a shared directory), which breaks because the server routes are simple REST endpoints which don't understand user authentication information (i.e. Meteor.user() doesn't work). The solution is to wrap the client-specific onBeforeAction calls with Meteor.isClient or simply move that code under the client directory. For example:

您的服务器端路由正在运行全局onBeforeAction代码(它在共享目录中定义),因为服务器路由是简单的REST端点,它们不了解用户身份验证信息(即Meteor.user()不起作用) 。解决方案是使用Meteor.isClient包装特定于客户端的onBeforeAction调用,或者只是将该代码移动到客户端目录下。例如:

if (Meteor.isClient) {
  Router.onBeforeAction(function () {
    if (!Meteor.user() || Meteor.loggingIn())
      this.redirect('welcome.view');
    else
      this.next();
    }
    ,{except: 'welcome.view'}
  );

  Router.onBeforeAction(function () {
    if (Meteor.user())
      this.redirect('home.view');
    else
      this.next();
    }
    ,{only: 'welcome.view'}
  );
}

Router.route('/pdf-server', function() {
  ...
}, {where: 'server'});

#1


8  

Your server-side routes are running the global onBeforeAction code (it's defined in a shared directory), which breaks because the server routes are simple REST endpoints which don't understand user authentication information (i.e. Meteor.user() doesn't work). The solution is to wrap the client-specific onBeforeAction calls with Meteor.isClient or simply move that code under the client directory. For example:

您的服务器端路由正在运行全局onBeforeAction代码(它在共享目录中定义),因为服务器路由是简单的REST端点,它们不了解用户身份验证信息(即Meteor.user()不起作用) 。解决方案是使用Meteor.isClient包装特定于客户端的onBeforeAction调用,或者只是将该代码移动到客户端目录下。例如:

if (Meteor.isClient) {
  Router.onBeforeAction(function () {
    if (!Meteor.user() || Meteor.loggingIn())
      this.redirect('welcome.view');
    else
      this.next();
    }
    ,{except: 'welcome.view'}
  );

  Router.onBeforeAction(function () {
    if (Meteor.user())
      this.redirect('home.view');
    else
      this.next();
    }
    ,{only: 'welcome.view'}
  );
}

Router.route('/pdf-server', function() {
  ...
}, {where: 'server'});