nodejs/ExpressJs和Angular中基于令牌的授权(单页应用)
Token based authorization in nodejs/ExpressJs and Angular(Single Page Application)
在我的应用程序中,当注册用户时,我在mongodb中保存用户名,密码和jwt生成的令牌。当用户尝试使用正确的凭据登录时,我将发送带有存储令牌的响应。然后在客户端(在我的控制器中),我使用localstorage来存储令牌,以便我可以为客户端发送的每个请求发送相同的令牌。但是我发现这个程序有一些问题:
- 我每次为一个用户生成相同的令牌。因此,如果任何第三方能够获得令牌,那么他就可以访问受限页面。
- 在MONGODB中存储生成的令牌是否浪费了db中的空间
- 除了用户之外,任何人都可以访问本地存储的令牌。
- 对于单页应用程序中的每个请求,我再次查询mongodb以获取该用户的令牌并进行验证。在这里,我正在检查客户端和服务器端。
我在我的应用程序中使用jwt生成令牌,Node,Express,Mongoose
我是否遵循了良好的程序。如果没有,能否提供我的方法或任何新的方法的解决方案。我搜索了许多基于令牌的授权和基于会话的授权网站,但对我来说没有任何作用。注意:我是Nodejs,AngularjS的初学者
你应该将令牌存储在高级键值缓存工具中,如:Redis这将显著提高性能。
你将从数据库第一次获得令牌,然后它应该存储在Redis中。我曾经设置令牌为键,用户名为值。下一个请求,令牌将从缓存中给出。使用Redis,你可以设置token的过期时间
当用户注册时,您需要像现在这样生成JWT。没关系。但是,您不需要将其保存到数据库中。你没有问,但我认为密码不应该以明文形式存储。你可以在保存到数据库之前使用bcrypt加密。
当用户尝试使用正确的凭据登录时,我将使用存储的令牌发送响应
对,这样做是正确的。
然后在客户端(在我的控制器中),我使用localstorage来存储令牌,以便我可以为客户端发送的每个请求发送相同的令牌。
是的,在客户端,您可以将JWT保存到本地存储,并在随后的请求中将其发送到服务器。
现在你的要点:
-
因此,您不会每次都有相同的JWT,您可以在有效负载中包含"exp"声明(我假设您正在使用JWT -simple之类的东西来生成JWT)。比如:
var payload = { sub: account.username, exp: moment().add(10, 'days').unix() }; var token = jwt.encode(payload, "secret");
-
您不需要在数据库中存储jwt。在某些情况下,令牌发行者(授权服务器)与资源服务器并不相同。资源服务器只接收请求中的jwt,但是资源服务器无法访问授权服务器使用的数据库。旁注:如果您最终需要支持刷新令牌,即您交给客户端的jwt最终需要过期,那么您可以将刷新令牌存储在数据库中。刷新令牌与jwt(访问令牌)不同。支持刷新令牌的复杂性将会增加。
-
本地存储不是存储密码的地方,但它可以用于存储jwt。正是由于这个原因,JWT必须而且应该在一定时间后过期。
-
不知道你说你检查客户端和服务器端是什么意思。当客户端需要访问资源时(同样可以假设资源服务器可能与授权服务器不同),传递给资源服务器的唯一内容就是JWT。任何人都可以解码JWT。例如,尝试将JWT粘贴到这个站点http://jwt.io/。这就是为什么JWT不应该包含任何敏感数据。但是,如果资源服务器知道授权服务器在编码JWT时使用的秘密,则资源服务器可以验证签名。回到您的第三个要点,这就是为什么可以将JWT存储在客户端的本地存储中。
更新我正在更新这篇文章,以回答你在评论框中的一些问题。
用户点击"Login"按钮会触发Angular控制器向服务器发送一个请求,比如:
$http.post(url, {
username: $scope.username,
password: $scope.password
}).success(function(res) { ... })
服务器接收POST请求,检查用户名/密码,然后生成JWT,并发送回浏览器。注意,它不必将JWT保存到数据库中。代码应该类似于
var payload = {
sub: account.username,
exp: moment().add(10, 'days').unix()
};
var token = jwt.encode(payload, "secret");
res.status(200).json({
token: token
});
回到客户端,在上面的success()回调中,现在您可以将JWT保存到本地存储中:
.success(function(res) { $window.localStorage.setItem('accessJWT', res.token) })
用户现在已通过身份验证。现在,当用户想要访问受保护的资源时,用户不必提供用户名/密码。有了可以从本地存储检索的JWT,客户端现在可以使用承载方案将JWT放入请求的Authorization header中,并将请求发送到服务器。在代码中,它像这样:
headers.Authorization = 'Bearer ' + token;
服务器接收请求。同样,接收此请求的服务器不必与生成上述JWT的服务器相同。这两个服务器可以位于两个不同的大洲。即使保存了上面的JWT,这对服务器也没有任何好处,因为它不能访问存储JWT的数据库。但是该服务器可以从请求的报头中提取承载令牌,验证令牌并继续执行正常任务。
希望这对你有帮助。
您不希望将JWT存储在mongoose中,因为它在登录时出现在标题中。首先生成一个令牌,然后使用crypto等模块对其进行散列。
有不同的方法可以做到这一点,它们都使用处理令牌的Passport。下面是一个示例项目Satellizer我建议你生成angular-fullstack项目。然后浏览服务器/认证文件夹和客户端/帐户文件夹。您将看到如何在基于MEAN的应用程序中安全地处理身份验证。
- 使用Javascript获取Twitter访问令牌
- FB.login访问令牌facebook javascript SDK
- React JS:未捕获(在承诺中)语法错误:在位置 0 的 JSON 中意外<令牌
- Phonegap:获取访问令牌时出现LinkedIn登录错误
- 授权客户端JS API调用Google'的具有现有访问令牌的gap库
- 谷歌'的用户令牌和授权代码
- 重定向时未找到授权令牌
- 收到错误 401 未经授权,无法在 Twitter 中验证 OAuth 签名和令牌
- 您如何处理需要使用 Angular 的授权令牌的下载链接
- 如何处理授权令牌
- JWT 返回无效签名错误,即使我在授权中输入令牌也是如此
- 令牌授权页面上的量角器测试
- 如何使用授权码获取访问令牌
- Angular Refresh令牌授权问题
- BOX API V2的授权令牌使用Netsuite的计划脚本获得
- 令牌认证/授权与PassportJS
- 从angularjs中的OAuth2授权端点中检索令牌
- Node express react oauth在与react客户端应用程序的回调中授权后通过访问令牌
- 从Javascript刷新Office365授权令牌
- nodejs/ExpressJs和Angular中基于令牌的授权(单页应用)