Aar*_*ron 10 authentication routing node.js meteor iron-router
为服务器端路由验证用户的最佳方法(最安全和最简单)是什么?
我正在使用最新的Iron Router 1.*和Meteor 1.*并开始,我只是使用帐户密码.
我有一个简单的服务器端路由,将pdf呈现给屏幕:
两者/ routes.js
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'});
Run Code Online (Sandbox Code Playgroud)
举个例子,我想做一些接近SO答案建议的事情:
在服务器上:
var Secrets = new Meteor.Collection("secrets");
Meteor.methods({
getSecretKey: function () {
if (!this.userId)
// check if the user has privileges
throw Meteor.Error(403);
return Secrets.insert({_id: Random.id(), user: this.userId});
},
});
Run Code Online (Sandbox Code Playgroud)
然后在客户端代码中:
testController.events({
'click button[name=get-pdf]': function () {
Meteor.call("getSecretKey", function (error, response) {
if (error) throw error;
if (response)
Router.go('/pdf-server');
});
}
});
Run Code Online (Sandbox Code Playgroud)
但即使我以某种方式使这个方法工作,我仍然容易受到用户只是放入像'/ pdf-server'这样的URL,除非路由本身以某种方式检查了Secrets集合吗?
在路线中,我可以得到请求,并以某种方式获取标题信息?
Router.route('/pdf-server', function() {
var req = this.request;
var res = this.response;
}, {where: 'server'});
Run Code Online (Sandbox Code Playgroud)
并且从客户端通过HTTP标头传递令牌,然后在路由中检查令牌是否来自Collection?
除了使用url令牌作为另一个答案,您还可以使用cookie:
添加一些允许您设置cookie并在服务器端读取它们的包:
meteor add mrt:cookies thepumpinglemma:cookies
Run Code Online (Sandbox Code Playgroud)
然后你可以有一些东西,使你的cookie与你的登录状态同步
客户端
Tracker.autorun(function() {
//Update the cookie whenever they log in or out
Cookie.set("meteor_user_id", Meteor.userId());
Cookie.set("meteor_token", localStorage.getItem("Meteor.loginToken"));
});
Run Code Online (Sandbox Code Playgroud)
服务器端
在服务器端,您只需要检查此cookie是否有效(使用铁路由器)
Router.route('/somepath/:fileid', function() {
//Check the values in the cookies
var cookies = new Cookies( this.request ),
userId = cookies.get("meteor_user_id") || "",
token = cookies.get("meteor_token") || "";
//Check a valid user with this token exists
var user = Meteor.users.findOne({
_id: userId,
'services.resume.loginTokens.hashedToken' : Accounts._hashLoginToken(token)
});
//If they're not logged in tell them
if(!user) return this.response.end("Not allowed");
//Theyre logged in!
this.response.end("You're logged in!");
}, {where:'server'});
Run Code Online (Sandbox Code Playgroud)
我认为我有一个安全而简单的解决方案,可以在IronRouter.route()中执行此操作.必须在标头中使用有效的用户ID和身份验证令牌进行请求.我在Router.route()中调用此函数,然后让我访问this.user,如果验证失败,则以401响应:
// Verify the request is being made by an actively logged in user
// @context: IronRouter.Router.route()
authenticate = ->
// Get the auth info from header
userId = this.request.headers['x-user-id']
loginToken = this.request.headers['x-auth-token']
// Get the user from the database
if userId and loginToken
user = Meteor.users.findOne {'_id': userId, 'services.resume.loginTokens.token': loginToken}
// Return an error if the login token does not match any belonging to the user
if not user
respond.call this, {success: false, message: "You must be logged in to do this."}, 401
// Attach the user to the context so they can be accessed at this.user within route
this.user = user
// Respond to an HTTP request
// @context: IronRouter.Router.route()
respond = (body, statusCode=200, headers) ->
this.response.statusCode statusCode
this.response.setHeader 'Content-Type', 'text/json'
this.response.writeHead statusCode, headers
this.response.write JSON.stringify(body)
this.response.end()
Run Code Online (Sandbox Code Playgroud)
来自客户的类似的事情:
Meteor.startup ->
HTTP.get "http://yoursite.com/pdf-server",
headers:
'X-Auth-Token': Accounts._storedLoginToken()
'X-User-Id': Meteor.userId()
(error, result) -> // This callback triggered once http response received
console.log result
Run Code Online (Sandbox Code Playgroud)
这段代码深受RestStop和RestStop2的启发.它是在Meteor 0.9.0+(构建在Iron Router之上)编写REST API的流星包的一部分.您可以在这里查看完整的源代码:
https://github.com/krose72205/meteor-restivus
由于服务器端路由充当简单的REST端点,因此它们无法访问用户身份验证数据(例如,他们无法调用Meteor.user()).因此,您需要设计另一种身份验证方案.实现这一目标的最直接的方法是通过这里和这里讨论的某种形式的密钥交换.
示例实现:
服务器/ app.js
// whenever the user logs in, update her apiKey
Accounts.onLogin(function(info) {
// generate a new apiKey
var apiKey = Random.id();
// add the apiKey to the user's document
Meteor.users.update(info.user._id, {$set: {apiKey: apiKey}});
});
// auto-publish the current user's apiKey
Meteor.publish(null, function() {
return Meteor.users.find(this.userId, {fields: {apiKey: 1}});
});
Run Code Online (Sandbox Code Playgroud)
LIB/routes.js
// example route using the apiKey
Router.route('/secret/:apiKey', {name: 'secret', where: 'server'})
.get(function() {
// fetch the user with this key
// note you may want to add an index on apiKey so this is fast
var user = Meteor.users.findOne({apiKey: this.params.apiKey});
if (user) {
// we have authenticated the user - do something useful here
this.response.statusCode = 200;
return this.response.end('ok');
} else {
// the key is invalid or not provided so return an error
this.response.statusCode = 403;
return this.response.end('not allowed');
}
});
Run Code Online (Sandbox Code Playgroud)
客户机/ app.html
<template name="myTemplate">
{{#with currentUser}}
<a href="{{pathFor route='secret'}}">secret</a>
{{/with}}
</template>
Run Code Online (Sandbox Code Playgroud)
让/secret只能通过HTTPS访问.
虽然请求的用户很可能/secret当前已连接,但不能保证她是.用户可能已登录,复制了她的密钥,关闭了选项卡,并在稍后的某个时间启动了请求.
这是一种简单的用户身份验证方法.如果服务器路由显示高价值数据(SSN,信用卡等),我会探索更复杂的机制(参见上面的链接).
有关从服务器发送静态内容的更多详细信息,请参阅此问题.
| 归档时间: |
|
| 查看次数: |
4382 次 |
| 最近记录: |