如何在Node.js和Redis中实现基于令牌的授权API?
我在一个web应用程序中工作,它处理来自Mongo数据库的资源,对于这些资源,我想提供一个API,以便未来的移动应用程序可以从原始客户端获取或使用它 然而,我希望web应用程序使用相同的API,在这里我对如何正确实现这一点感到困惑 以下是我迄今为止所做的工作: API认证: 所以基本上我接收消费者的用户名和密码,根据数据库对其进行身份验证,如果匹配,我回复一个令牌(实际上是一个如何在Node.js和Redis中实现基于令牌的授权API?,node.js,api,authentication,Node.js,Api,Authentication,我在一个web应用程序中工作,它处理来自Mongo数据库的资源,对于这些资源,我想提供一个API,以便未来的移动应用程序可以从原始客户端获取或使用它 然而,我希望web应用程序使用相同的API,在这里我对如何正确实现这一点感到困惑 以下是我迄今为止所做的工作: API认证: 所以基本上我接收消费者的用户名和密码,根据数据库对其进行身份验证,如果匹配,我回复一个令牌(实际上是一个UUID)。该令牌与数据库中的用户id成对存储在Redis中。将来对任何API路由的每个请求都将验证这种令牌是否存在 我
UUID
)。该令牌与数据库中的用户id成对存储在Redis中。将来对任何API路由的每个请求都将验证这种令牌是否存在
我想知道:
- 我应该如何管理令牌TTL,以及在将来请求时续订?
- 如何控制每次请求的时间窗口限制?
- 我采取的方法中是否有任何安全警告?
POST/api/auth
身份验证是有意义的。
我想知道:
- 这是最好的方法吗?
- 我是否应该包含任何标记盐来区分纯API消费请求和web应用请求?
- 我采取的方法中是否有任何安全警告?
- 我应该包括更多代币吗?
POST/login
的示例:
app.route('/login')
.post(function (request,response,next) {
var email = request.body.email;
var password = request.body.password;
var login = new Account({"local.email":email,"local.password":password});
Account.findOne({"local.email":email}, function (err,user) {
if (err) {
response.redirect('/error');
}
if (!user) {
var cookie = request.cookies.userAttempts;
if (cookie === undefined) {
response.cookie('userAttempts',1);
}
else {
response.cookie('userAttempts',(++cookie));
}
response.redirect('/');
}
else {
user.validPassword(password, function (err,matched) {
if (err) {
// Redirect error site or show err message.
response.redirect('/error');
}
if (matched) {
var session = request.session;
session.userid = user._id;
var uuidToken = uuid.v4();
redisClient.set(uuidToken,user._id,redis.print);
redisClient.expire(uuidToken,900);
response.cookie('email',email);
response.redirect('/start');
}
else {
var cookie = request.cookies.passwordAttemps;
if (cookie === undefined)
response.cookie('passwordAttemps',1);
else {
var attemps = ++request.cookies.attemps
response.cookie('passwordAttemps', attemps)
}
response.redirect('/');
}
});
}
});
})
我想我可以不用使用和编写典型的会话实现,而以某种方式依赖API所具有的类似基于令牌的身份验证。您所拥有的一切都是正确的,基本上取代了Cookie的一些功能。有一些事情要考虑,你已经接触了其中一些。
如果您确实使用了我们的API,那么该模块的API界面上出现了一个分裂,您可以选择直接将数据存储在JWT声明或redis中,这似乎有些奇怪。这是经过深思熟虑的,我认为您的示例为双方都说明了一个很好的用例。通常我们要做的是将用户的电子邮件和姓名存储在JWT声明中,然后将更多动态会话数据存储在他们会话的redis中。例如,在登录时,您可以将发行人、受众和用户的电子邮件添加到JWT声明中,但不要添加任何与“userAttempts”相关的内容。然后,在尝试失败后,您将添加或修改与该JWT相关的redis中存储的会话数据上的“userAttempts”。一旦设置了JWT,就不可能在不生成新JWT的情况下修改其内容,因此请注意,如果您决定在JWT中保留相对动态的数据,服务器和客户端之间将不断交换新旧JWT。非常感谢您提出的扩展问题。我想我会考虑使用JWT。到目前为止,网站需要进行身份验证
app.route('/login')
.post(function (request,response,next) {
var email = request.body.email;
var password = request.body.password;
var login = new Account({"local.email":email,"local.password":password});
Account.findOne({"local.email":email}, function (err,user) {
if (err) {
response.redirect('/error');
}
if (!user) {
var cookie = request.cookies.userAttempts;
if (cookie === undefined) {
response.cookie('userAttempts',1);
}
else {
response.cookie('userAttempts',(++cookie));
}
response.redirect('/');
}
else {
user.validPassword(password, function (err,matched) {
if (err) {
// Redirect error site or show err message.
response.redirect('/error');
}
if (matched) {
var session = request.session;
session.userid = user._id;
var uuidToken = uuid.v4();
redisClient.set(uuidToken,user._id,redis.print);
redisClient.expire(uuidToken,900);
response.cookie('email',email);
response.redirect('/start');
}
else {
var cookie = request.cookies.passwordAttemps;
if (cookie === undefined)
response.cookie('passwordAttemps',1);
else {
var attemps = ++request.cookies.attemps
response.cookie('passwordAttemps', attemps)
}
response.redirect('/');
}
});
}
});
})