我已在 api.com 的服务器上开发了无状态API 。某些API端点需要身份验证。
我在 website.com 的单独服务器上有网站。当用户对网站进行身份验证时,网站服务器需要从API端点检索一些需要身份验证的数据(例如/tweets
)。此数据将用于服务器响应(例如,用于呈现推文)。
服务器响应还将在浏览器中下载一些JavaScript,随后需要从API端点检索(通过XMLHttpRequests(XHR))一些数据,例如需要身份验证(/tweets
)。
此架构代表同构Web应用程序。服务器在请求时呈现整个页面,然后客户端使用JavaScript处理用户操作。
-
在非常基础的层面上,我可以对website.com和api.com使用HTTP基本身份验证。但是,浏览器会在首次登录website.com时提示用户输入凭据,并在客户端向需要身份验证的端点进行XHR时反复输入。
我希望用户在website.com上使用他们的凭据登录一次。这与当前的Twitter网站类似。登录到twitter.com后,网站服务器会将您识别为已通过身份验证,并使用包含JavaScript下载的HTML页面进行响应。然后,JavaScript应用程序(可能)将经过身份验证的XHR发送到无状态Twitter API。
API是一个单独的服务器设计。最终API可以为第三方开放,尽管这不是最初的要求。
我怎样才能做到这一点?我正在寻找:
两者都很棒!
答案 0 :(得分:9)
您描述的情况正是OAuth的设计目标:客户端使用一台服务器进行授权,然后获取对另一台服务器上资源的访问权限。在您的情况下,website.com是授权服务器,api.com是资源服务器。简而言之,授权服务器向客户端发送访问令牌,然后客户端可以将访问令牌传递给资源服务器以证明他们有权访问资源。为了使其工作,资源服务器(api.com)需要使用授权服务器(website.com)进行检查以验证令牌是有效的还是事先被告知令牌。因此,客户端,授权服务器和资源服务器之间存在三角形通信,其中传递共享密钥。因此,绝对有必要在链的所有部分使用安全连接(HTTPS);否则,有人可以拦截令牌并伪装成授权客户。通过使用无法完全验证用户身份的有限访问令牌,将其保持在合理范围内,但仍然是您应该尝试阻止的问题。
虽然理论上很安全,但OAuth是一个复杂的系统,很难做到正确。有些人认为实际上不可能做对(尤其是Eran Hammer,OAuth 2.0规范的原始主要作者,他决定退出工作组)。但是,鉴于您无论如何都需要使用HTTPS,您可以完全避免使用OAuth,而是使用HTTPS(或实际上是TLS)的一个鲜为人知的内置功能(称为!surprise!)客户端身份验证。
您可能已经知道,在HTTPS协议中,服务器(website.com)使用由受信任机构签名的证书来验证自身。这是一个很好理解且非常安全的机制(至少通过互联网标准),只要证书不妥协并且使用最新版本的TLS。客户端也可以这样做,即使用由受信任的机构签名的证书进行身份验证。后一个权限可以是服务器(website.com),因为服务器可以信任自己。因此,TLS客户端身份验证的优雅之处在于客户端无需联系第三方即可获取证书;客户端和服务器可以合作为客户端提供服务器可以信任的证书。这甚至可能非常用户友好,因为客户端证书只需要传输和安装一次,然后可以用于后续会话的身份验证,可能没有用户甚至需要输入密码。相同的客户端证书也可以用于与其他服务器(例如api.com)的HTTPS连接,前提是这些服务器知道证书并信任签署它的权限(website.com)。
TLS客户端身份验证可能比OAuth更安全,而整体用户可能需要更少的交互(取决于在浏览器中处理客户端证书的方式)。另一方面,大多数用户可能不熟悉TLS客户端身份验证的特定机制。如果用户需要从许多不同的设备登录或需要对许多不同的服务器进行身份验证,则此工作流程可能会令人困惑或麻烦,因为每个设备都需要有证书,并且当新服务器时用户可能必须手动选择证书是第一次参观。
总结:
对评论的一些澄清:
website.com如何知道用户已登录? website.com如何记住用户已登录(即浏览器刷新之间)?
将访问令牌存储在客户端的安全cookie中。在客户端对website.com的每个请求中,访问令牌都包含在请求标头中。通过这种方式,website.com可以确保每个请求都经过身份验证(如果请求包含访问令牌,即用户已登录),或者访问者是访客。
浏览器如何进行经过身份验证的XHR请求?
通过在请求标头中发送访问令牌,就像对于website.com一样。显然,这需要客户端访问cookie。
在创建服务器响应时,website.com需要通过api.com进行身份验证
当它这样做时,它只是代表用户发送(HTTPS)请求。访问令牌包含在请求标头中也是一样的。 website.com在执行此操作时始终具有用户的访问令牌,因为它要么将其提供给用户,要么只是从用户那里接收到它。
有关维基百科的更多信息:
答案 1 :(得分:1)
正如朱利安所说,OAuth很复杂,很难做对。我会找到一个受信任的开源项目,并将其用作您的身份服务器。
此外,我将研究OpenID Connect,而不是OAuth。这是一个相对较新的协议(2014年1月),但一直受到很多关注。例如,Google +正在使用它。它结合了OAuth的授权框架,并在顶部添加了身份和身份验证框架。 OAuth从未真正为此设计,这也是Eran离开项目的原因之一。这个新协议是Single Sign On的未来,将取代WS-Federation和SAML。 http://openid.net/connect/
以下是所有可用的库:http://openid.net/developers/libraries/
同样,如果您正在使用C#/ .NET,那么这是他们目前在Beta 3中的项目(应该在Januaray中使用),它提供了每个可能的可配置方案和示例。如果没有别的,它会为您提供代码,以了解如何实现它。 https://github.com/thinktecture/Thinktecture.IdentityServer.v3.Samples
有关详细信息,请参阅此演讲:http://vimeo.com/97344501
希望这会给你一些思考的食物。
答案 2 :(得分:0)
我认为可以做到这样的事情
1)用户登录website.com,website.com将为未来的API使用创建临时令牌T
2)每当api.com需要一些数据时,网站都会请求该数据并在请求中发送令牌T api.com/getdata/params = ...& token = T
使用SSL可以更好地完成此请求以保护令牌。
另请检查http://en.wikipedia.org/wiki/Cross-origin_resource_sharing - 并非所有浏览器都允许您从Javascript请求来自其他域的数据。
3)当api.com收到此类请求时,它将与website.com建立单独的秘密连接,例如website.com/checktoken/?token=T,并获取有关该网站用户的所有必要信息。 com向他发送相关数据
4)用户获取所有信息,而不是离开website.com而不必在两个地方进行身份验证
答案 3 :(得分:0)
基本上,您需要决定是否要授权 website.com 域使用 api.com 方法,或者授权< website.com 的em> users 使用 api.com 。从您的描述中我了解到您正在谈论第二种情况。
然后,某些OAuth(OAuth2.0)实现可能适合您(可能)所有站点的单个身份验证点:它可能是 passport.com 。当用户想要使用 api.com 或 website.com 或任何其他网站时,他将被重定向到 passport.com 并要求在那里验证。在 passport.com 上进行身份验证后,将重定向用户并提供授权代码,该代码用于请求令牌,而后者可由 api.com 和 website.com 以获取有关用户的信息(角色,权限等)。在 website.com 上,您可以使用此令牌访问 api.com ,因为 api.com 可以使用此令牌来验证用户对 passport.com 。您也可以使用此令牌通过AJAX从 api.com 请求信息(但您需要克服同源策略问题,但它可行)
更新:
想法是用户需要在 passport.com 上进行身份验证才能使用 website.com &amp; api.com 。 从OAuth2.0的角度来看,您可以说用户授权 website.com &amp; api.com 在 passport.com 上使用他的信息。 因此,身份验证cookie仅适用于 passport.com 域和 不会发送到任何其他地方( website.com 或 api.com )。这是根据同源政策。
在您的情况下,对OAuth2.0实现的更详细描述将是:
用户希望(或必须)在 website.com 上进行身份验证。执行 passport.com 的请求(在 website.com上指定REDIRECT_URL 以后返回):passport.com/auth/?redirectTo=REDIRECT_URL
如果用户未在 passport.com 上进行身份验证(那里没有Auth cookie),则会向他显示 passport.com 的登录页面。经过身份验证后,新的AUTHORIZATION_CODE将保存在该用户的 passport.com (在数据库中)中。
在 passport.com 上进行身份验证后(或者如果用户已在此处进行身份验证) passport.com 将用户重定向回REDIRECT_URL,并使用查询字符串中的AUTHORIZATION_CODE:{REDIRECT_URL }?代码= AUTHORIZATION_CODE
Website.com 使用此AUTHORIZATION_CODE从 passport.com 请求ACCESS_TOKEN: passport.com/token/?code=AUTHORIZATION_CODE
拥有ACCESS_TOKEN, website.com 可以使用它从 passport.com 请求有关用户的信息。另外,当您从 api.com 请求内容时,您可以将此ACCESS_TOKEN传递给 api.com 。 api.com 可以检查用户对 passport.com 的身份,以检查他是否拥有足够的权限。将ACCESS_TOKEN传递给 api.com 是否安全?无论如何,你需要提供 api.com 的某种键(如果 api.com 不是公共API),所以使用这种方法至少ACCESS_TOKEN不是静态的一:它有生命周期,而且是基于用户的。
同样,它是非常简化的OAuth2.0示例,没有密钥,范围,访问授权和其他一些细节。
答案 4 :(得分:0)
这是一种简单的方法。它增加了一些开销/延迟,但至少它起作用并且很简单:
让website.com充当代理并转发所有对api.com的电话
browser <-> https://website.com/api/url <-> https://api.com/url
您可以重复使用creditentials来建立从website.com到api.com的单独会话