智威汤逊前端和后端令牌战略

我在一个nodejs服务器中编写一个前端应用程序在emberjs和后端/服务器端。 我有emberjsconfiguration,以便用户可以login/注册与第三方Oauth(谷歌,微博,Facebook)。 我有一个后端编写在承载RESTful API的express nodejs服务器上。

我没有DB连接到emberjs,我不认为我应该反正,因为它是严格的客户端代码。 我打算使用JWT进行客户端和服务器端之间的通信。 当用户使用他们的oauth信誉login时,我从提供者的uid,name,login,access_token和其他细节中得到一个JSON对象。

我正在努力挑选如何处理用户注册的策略。 由于是OAuth,因此没有注册stream程。 所以stream程是如果用户不在我的分贝,创build它。 我不支持电子邮件/密码authentication。 用户首次使用OAuth提供商login时会有什么stream量? 应该emberjs发送所有的细节到每个login后端,以便后端可以添加新的用户到数据库?

什么应该是我的JWT机构的一部分? 我在想用户和供应商提供的访问令牌。 我能想到的一个问题是提供者特定的访问令牌可以改变。 用户可以从供应商的网站撤消令牌,并用emberjs再次注册。

我打开写在任何其他JavaScript客户端框架的前端,如果它变得更容易。

如果我们谈论的不仅是工作而且是安全的无状态身份validation,您将需要考虑accessrefresh令牌的正确策略。

  1. 访问令牌是提供对受保护资源的访问的令牌。 这里的Expiration可能会在大约1小时内安装(取决于您的考虑)。

  2. 刷新令牌是一个特殊的令牌,应该用来生成额外的access token ,以防过期或用户会话更新。 很明显,你需要使它长久(与access token相比),并尽可能地安全。 这里的Expiration可能会在大约10天甚至更多的时间内安装(也取决于您的考虑)。

仅供参考:由于refresh tokens长期存在,为了使它们真正安全,您可能希望将它们存储在数据库中(刷新令牌请求很less执行)。 这样一来,即使你的刷新令牌以某种方式被黑客攻击,并且有人重新生成了access/refresh令牌,当然你也会失去权限,但是你仍然可以login系统,因为你知道login/通行证(如果你稍后会使用它们),或者只是通过任何社交networkinglogin。


在哪里存储这些令牌?

基本上有两个共同的地方:

  1. HTML5 Web存储 (localStorage / sessionStorage)

很好去,但在同一时间足够的风险。 存储是通过JavaScript代码在同一个域上访问。 这意味着如果你有XSS ,你的代币可能会被黑客入侵。 所以通过select这种方法,你必须小心,编码/转义所有不受信任的数据。 即使你这样做,我敢肯定你使用了一些第三方客户端模块,并不能保证他们有一些恶意代码。

此外, Web Storage在传输过程中不执行任何安全标准。 所以你需要确定JWT是通过HTTPS发送的,而不是HTTP

  1. cookies

使用特定的HttpOnly选项cookie不能通过JavaScript访问,并且不受XSS影响。 您还可以设置Secure cookie标记以保证cookie仅通过HTTPS发送。 但是,Cookie很容易受到不同types的攻击:跨站请求伪造( CSRF )。 在这种情况下,可以通过使用某种同步的令牌模式来阻止CSRF 。 在安全注意事项部分, AngularJS有很好的实现。

您可能想要遵循的文章 。

为了说明它是如何工作的:

http://jlabusch.github.io/oauth2-server/img/diag_refresh_token.png


关于智威汤逊本身几句话:

为了说清楚,从Auth0开始,真的很酷的JWTdebugging器 。 有2(有时是3)常见的索赔types: publicprivate (和保留 )。

JWT机构的一个例子(有效载荷,可以是任何你想要的):

 { name: "Dave Doe", isAdmin: true, providerToken: '...' // should be verified then separately } 

有关JWT结构的更多信息,请点击这里 。

回答你提出的两个具体问题:

用户首次使用OAuth提供商login时会有什么stream量? 应该emberjs发送所有的细节到每个login后端,以便后端可以添加新的用户到数据库?

每当用户通过oauth注册或login,并且您的客户端收到一个新的访问令牌时,我会将其更新或插入到您的用户表(或集合)中,以及您检索到的任何新的或更新的信息来自oauth提供者API的用户。 我build议将其直接存储在每个用户logging上,以确保访问令牌和关联的configuration文件信息以primefaces方式更改。 一般来说,我通常会将这种情况写入某种中间件,当新的令牌出现时自动执行这些步骤。

什么应该是我的JWT机构的一部分? 我在想用户和供应商提供的访问令牌。 我能想到的一个问题是提供者特定的访问令牌可以改变。 用户可以从供应商的网站撤消令牌,并用emberjs再次注册。

JWT机构一般由用户声明组成 。 我个人认为将提供者访问令牌存储在JWT令牌的主体中几乎没有什么好处,因为它对您的客户端应用程序没有多less好处(除非您正在从您的客户端向API执行大量直接API调用,我更愿意那些调用服务器端,并发送我的应用程序客户端返回一套规范化的声明,坚持我自己的接口)。 通过编写自己的声明界面,您将不必从客户端应用程序中解决多个提供程序所带来的各种差异。 这样做的一个例子就是将Twitter和Facebook的特定字段在其API中以不同方式命名为您存储在用户个人资料表中的常见字段,然后将您的本地configuration文件字段作为声明embedded您的JWT主体中,以供客户端应用程序解释。 还有一个额外的好处是,你将不会在未encryption的JWT令牌中保存将来可能泄漏的任何数据。

无论您是否将oauth提供程序提供的访问令牌存储在JWT令牌主体中,每次configuration文件数据更改时都需要授予新的JWT令牌(如果没有configuration文件更新,您可以放入机制以绕过发放新的JWT令牌发生了,以前的令牌还是不错的)。

除了在JWT标记主体中存储为声明的任何configuration文件字段之外,我还将始终定义标准的JWT标记主体字段 :

 { iss: "https://YOUR_NAMESPACE", sub: "{connection}|{user_id}", aud: "YOUR_CLIENT_ID", exp: 1372674336, iat: 1372638336 } 

对于任何OAuth工作stream程,您都应该使用passportjs库。 你也应该阅读完整的文档。 这很容易理解,但是我犯了第一次没有读完整个事情的错误,并且挣扎了。 它包含超过300个提供商和颁发令牌的OAuthauthentication。

尽pipe如此,如果你想手动或想要一个基本的理解,这里是我将使用的stream程:

  1. 前端有一个login页面列表login与谷歌/ Facebook等OAuth实施。

  2. 成功的OAuth导致一个uid,login,access_token等(JSON对象)

  3. 您将JSON对象发布到您的Node.js应用程序中的/login/ route。 (是的,无论是新用户还是现有用户,都会发送整个响应。在这里发送额外的数据比做两个请求要好)

  4. 后端应用程序读取uidaccess_token 。 通过遵循( https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow#checktoken )或使用访问令牌从提供者询问用户数据,确保access_token有效。 (由于OAuth访问令牌是以每个应用程序/开发者为基础生成的,因此无效访问令牌会失败)现在,search您的后端数据库。

  5. 如果数据库中存在uid ,则更新数据库中用户的access_token和expiresIn。 (access_token可以让你从那个特定的用户那里得到更多的Facebook信息,而且它通常提供几个小时的访问。)

  6. 否则,你创build一个新的用户与uid,login等信息。

  7. 更新access_token或创build新用户之后,您将发送包含uid JWT令牌。 (用一个秘密对jwt进行编码,这将确保它是由你发送的,并且没有被篡改过。https://github.com/auth0/express-jwt

  8. 在用户从/login接收到jwt之后的前端,通过sessionStorage.setItem('jwt', token);将其保存到sessionStorage sessionStorage.setItem('jwt', token);

  9. 在前端,还添加以下内容:

if ($window.sessionStorage.token) { xhr.setRequestHeader("Authorization", $window.sessionStorage.token); }

这将确保如果有一个jwt令牌,它随每个请求一起发送。

  1. 在你的Node.js app.js文件中,添加

app.use(jwt({ secret: 'shhhhhhared-secret'}).unless({path: ['/login']}));

这将validation您的path中的任何东西的jwt,确保用户login,否则不允许访问和redirect到login页面。 这里的exception情况是/login因为这是您为新的或未经/loginvalidation的用户提供JWT的地方。

您可以在Githuburl上find更多关于如何获取令牌的信息,并找出您当前正在服务的用户请求。