在不违反 RESTful 原则的情况下,在 Angular 中进行身份验证和授权的最佳实践?

Posted

技术标签:

【中文标题】在不违反 RESTful 原则的情况下,在 Angular 中进行身份验证和授权的最佳实践?【英文标题】:Best practices for authentication and authorization in Angular without breaking RESTful principles? 【发布时间】:2014-04-24 16:00:12 【问题描述】:

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

    访客访问受限 通过身份验证后对应用程序的基于角色的访问 通过 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 best practice application authentication),但除非我误解了答案,否则似乎暗示应该使用服务器会话,这违反了 RESTful 原则。

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

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

POST /api/session

为用户创建一个新会话

要创建会话,您需要 POST 包含“用户名”和“密码”的 JSON 对象。


    "email" : "austen@example.com",
    "password" : "password"

卷曲示例

curl -v -X POST --data '"username":"austen@example.com","password":"password"' "https://app.example.com/api/session" --header "Content-Type:application/json"

回应

HTTP/1.1 201 Created 
    "session": 
        "id":"520138ccfa4634be08000000",
        "expires":"2014-03-20T17:56:28+0000"
    

状态代码

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

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

Authorization: MyScheme 520138ccfa4634be08000000 

然后后端服务器将负责从请求中提取此内容,查找关联的用户并执行请求的授权规则。它可能也应该更新会话的到期时间。

如果这一切都发生在 SSL 上,我是否会对我应该防范的任何类型的攻击敞开大门?您可以尝试猜测会话密钥并将它们放在标题中,所以我想我可以另外将用户 GUID 附加到会话密钥以进一步防止暴力攻击。

我已经有好几年没有主动编程了,我才刚刚回到这里。抱歉,如果我是迟钝或不必要地重新发明***,只是希望根据我目前的阅读情况在这里的社区运行我的想法,看看他们是否通过了试金石。

【问题讨论】:

不完全相关,但这可能会让您感兴趣:youtube.com/watch?v=62RvRQuMVyg(第一部分处理身份验证,它们生成 index.html 服务器端并在其中包含配置文件,我在我的应用) 感谢分享,我稍后会检查一下! 【参考方案1】:

这是一篇关于使用 Angular 构建的身份验证和登录服务的令人难以置信的文章。

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

【讨论】:

这是一篇很棒的文章,我可能会使用所讨论的一些技术,但它确实没有回答我的主要问题,即登录后如何验证后续请求(除非我遗漏了什么)。验证/授权服务器端所需的信息需要作为每个后续 REST 请求的一部分传递,才能真正实现无状态。从安全角度来看,我的上述攻击计划是否足够,还是有其他更好的技术?【参考方案2】:

这个 SO question 很好地总结了我对 REST 的理解

Do sessions really violate RESTfulness?

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

我想知道您创建 RESTful 服务的原因是什么,因为也许这并不是一个大问题。

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

长话短说,我认为以 RESTful 实现为目标是一个不错的目标,但在身份验证和验证授权方面,纯粹的无状态肯定会增加一层复杂性。

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

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

【讨论】:

废话。您不知道该令牌在何处或如何进行身份验证。服务器可以很容易地将其移交给其他一些(RESTful)基础设施。令牌仅代表过期的租约。令牌并不意味着会话。会话不是特别安静,令牌......只是令牌。 非常真实的Will Hartung,我在这里解释的不是很好,把一些事情搞混了,有机会深入思考后我会尝试纠正。出于好奇,您能否详细说明您将如何生成、存储和验证令牌?在阅读了你所说的之后,我确实意识到有几种方法,我在以一种封闭的方式思考。【参考方案3】:

当有人询问 REST 身份验证时,我遵从 Amazon Web Services 并基本上建议“这样做”。为什么?因为,从“大众智慧”的角度来看,AWS 解决了问题,被人们大量使用、大量分析和审查,这些人比大多数人更了解和关心什么是安全请求。安全是“不重新发明***”的好地方。在“肩膀要站”这件事上,你可以做得比 AWS 差。

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

但它有效。

缺点是它要求您的应用程序保留个人共享机密(即密码),并且它还要求服务器可以访问该密码的纯文本版本。这通常意味着密码被加密存储,然后在适当的时候解密。与安全散列技术相比,这会导致密钥管理和服务器端的其他事情变得更加复杂。

当然,任何令牌传递技术的最大问题是中间人攻击和重放攻击。 SSL 自然地主要缓解了这些问题。

当然,您还应该考虑 OAuth 系列,它们有自己的问题,尤其是互操作性,但如果这不是主要目标,那么这些技术肯定是有效的。

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

您仍然对(潜在的)重放问题持开放态度,相同的请求可能会被发送两次。对于典型的散列实现,时间戳是签名的一部分,可以将请求的生命周期括起来。在这种情况下,解决方法不同。例如,可以使用序列号或 GUID 发送每个请求,并且您可以记录该请求已经播放过,以防止再次发生。不同的技术。

【讨论】:

谢谢,威尔,这很有帮助! AWS 技术与更通用的 JSON Web Token (JWT, jwt.io) 非常相似。我认为 JWT 是更好的框架。

以上是关于在不违反 RESTful 原则的情况下,在 Angular 中进行身份验证和授权的最佳实践?的主要内容,如果未能解决你的问题,请参考以下文章

在不违反 SRP、OCP、DRY 的情况下编写测试

如何在不违反主键约束的情况下插入具有循环引用的实体框架

如何在不违反命令和查询端分离的情况下基于元数据在 CQRS 中构建查询

如何在不违反 CSP 的情况下绑定剃须刀视图中的 onchange 等事件

如何在不更新 APK 文件的情况下解决违反使用 Android 广告 ID 政策和第 4.8 节的问题 [重复]

C++:在不违反 SRP 的情况下向多态类层次结构添加方法?