Angular中不违背RESTful原则的认证和授权的最佳实践



我已经读了不少关于REST和Angular的身份验证和授权的SO线程,但我仍然觉得我没有一个很好的解决方案来解决我希望做的事情。对于一些背景,我计划在AngularJS中构建一个应用程序,我想支持:

  1. 限制访客访问
  2. 通过身份验证后基于角色访问应用程序
  3. api认证

所有对REST API的调用都需要通过SSL进行。我想在不打破RESTful原则的情况下构建应用程序,即不保留存储在服务器上的会话状态。当然,在客户端针对授权所做的任何工作都必须在服务器端得到加强。由于我们需要为每个请求传递整个状态,因此我知道我需要传递某种令牌,以便接收REST请求的后端服务器能够对调用进行身份验证和授权。

话虽如此,我的主要问题是关于身份验证的——这里的最佳实践是什么?似乎有很多不同的方法被讨论,这里只是我发现的一些:

  • http://broadcast.oreilly.com/2009/12/principles-for-standardized-rest-authentication.html
  • http://frederiknakstad.com/2013/01/21/authentication-in-single-page-applications-with-angular-js/
  • http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html

有一个类似的问题(AngularJS最佳实践应用程序身份验证),但除非我误解了答案,否则它似乎暗示应该使用服务器会话,这违反了RESTful原则。

我对Amazon AWS和George Reese文章的主要担忧是,它似乎假设消费者是一个程序,而不是最终用户。共享密钥可以提前发给程序员,然后程序员可以使用它在这里对调用进行编码。这不是这里的情况-我需要代表用户从应用程序调用REST API。

这种方法足够吗?假设我有一个会话资源:

POST/api/会话

为用户创建一个新会话

创建一个会话,你需要POST一个JSON对象,包含"用户名"one_answers"密码"。

{
    "email" : "austen@example.com",
    "password" : "password"
}
<<p> 旋度例子/strong>
curl -v -X POST --data '{"username":"austen@example.com","password":"password"}' "https://app.example.com/api/session" --header "Content-Type:application/json"
<<p> 反应/strong>
HTTP/1.1 201 Created {
    "session": {
        "id":"520138ccfa4634be08000000",
        "expires":"2014-03-20T17:56:28+0000"
    }
}

状态代码

  • 2011 -创建,新会话建立
  • 400 -错误请求,JSON对象无效或缺少所需信息
  • 401 -未经授权,检查电子邮件/密码组合
  • 403 -拒绝访问,禁用帐户或许可证无效

为了清楚起见,我省略了HATEOAS的细节。在后端,将创建一个新的、有限持续时间的会话密钥并与用户关联。在随后的请求中,我可以将其作为HTTP头的一部分传递:

Authorization: MyScheme 520138ccfa4634be08000000 

然后后端服务器将负责从请求中提取这些信息,查找相关的用户并为请求执行授权规则。它可能还应该更新会话的过期时间。

如果所有这些都是通过SSL发生的,我是否为我应该防范的任何类型的攻击敞开了大门?您可以尝试猜测会话密钥并将其放在报头中,因此我认为可以在会话密钥中附加一个用户GUID,以进一步防止暴力攻击。

我已经有好几年没有积极地编程了,我刚刚回到这里。如果我很迟钝或不必要地重新发明轮子,我只是希望在社区中运行我的想法,基于我到目前为止的阅读,看看它们是否通过了石蕊试金石

当有人询问REST身份验证时,我遵从Amazon Web Services,基本上建议"那样做"。为什么?因为,从"群体智慧"的角度来看,AWS解决了问题,它被大量使用、大量分析和审查,而这些人比大多数人更了解和关心什么是安全请求。而安全是一个"不用重新发明轮子"的好地方。就"站在肩膀上"而言,你可能比AWS做得更差。

现在,AWS不使用令牌技术,而是使用基于共享秘密和有效负载的安全哈希。它可以说是一个更复杂的实现(包括它所有的规范化过程,等等)。

但它有效。

缺点是它要求您的应用程序保留人员共享的秘密(即密码),并且它还要求服务器访问该密码的纯文本版本。这通常意味着密码是加密存储的,然后在适当的时候进行解密。与安全哈希技术相比,这会增加服务器端密钥管理和其他事情的复杂性。

当然,对于任何令牌传球技术来说,最大的问题是中场进攻和重放攻击。SSL在很大程度上缓解了这些问题。

当然,您还应该考虑OAuth家族,它们有自己的问题,特别是互操作性,但如果这不是主要目标,那么这些技术当然是有效的。

对于您的应用程序,令牌租赁不是什么大问题。您的应用程序仍然需要在租约的期限内运行,或者能够续订租约。为此,它需要保留用户凭据或重新提示用户凭据。就像对待其他任何东西一样,将令牌视为一级资源。如果可行,尝试将一些其他信息与请求关联,并将其捆绑到令牌中(浏览器签名,IP地址),只是为了强制一些局部性。

您仍然有(潜在的)重放问题,其中相同的请求可以发送两次。对于典型的散列实现,时间戳是签名的一部分,它可以将请求的生命周期括起来。在这种情况下,解决方法不同。例如,每个请求都可以发送一个串行ID或GUID,您可以记录请求已经播放,以防止再次发生。不同的技巧。

这是一篇关于用angular构建身份验证和登录服务的文章。

https://medium.com/opinionated-angularjs/7bbf0346acec

这个问题很好地总结了我对REST的理解

会话真的违反rest吗?

如果你在会话中存储令牌,你仍然在服务器端创建状态(这是一个问题,因为会话通常只存储在一台服务器上,这可以通过粘性会话或其他解决方案来缓解)。

我想知道你创建RESTful服务的理由是什么,因为这可能不是一个大问题。

如果您在每个请求中发送令牌(因为所有内容都使用SSL加密,这是可以的),那么您可以有任意数量的服务器(负载均衡)服务于请求,而无需任何先前的状态知识。

长话短说,我认为以RESTful实现为目标是一个很好的目标,但是当涉及到身份验证和验证授权时,纯粹的无状态肯定会增加额外的复杂性。

到目前为止,我已经开始用REST构建我的后端,制作有意义的uri并使用正确的HTTP动词,但仍然在会话中使用令牌以简化身份验证(当不使用多个服务器时)。

我看了你发布的链接,AngularJS似乎只关注客户端,在那篇文章中似乎没有明确地解决服务器问题,他确实链接到另一篇(我不是Node用户,所以如果我的解释在这里是错误的,请原谅我),但服务器似乎依赖于客户端来告诉它它拥有什么级别的授权,这显然不是一个好主意。

最新更新