javascript 使用带有本地策略的 CORS 向 REST API 验证客户端应用程序

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15286324/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 00:12:50  来源:igfitidea点击:

Authenticate client-side app to REST API using CORS with local strategy

javascriptnode.jsangularjs

提问by Dan Kanze

The Problem:

问题:

Serving a secure API to a client side app using only a local authentication strategy.
The red arrows are part of the knowledge gap.

仅使用本地身份验证策略为客户端应用程序提供安全 API。
红色箭头是知识差距的一部分。

enter image description here

在此处输入图片说明

Context:

语境:

That is --- client.example.comis making a POSTto api.example.com/loginwhere on success client.example.comcan gain access to a GETservice like api.example.com/secret.

也就是说 ---client.example.com正在向成功可以访问GET服务的地方发出POST请求api.example.com/login,例如.client.example.comapi.example.com/secret

An idea!

一个想法!

Implimentation of OAuth 2.0 with hybrid grant type sitting in front of API.

使用位于 API 前面的混合授权类型实现 OAuth 2.0。

Why hybrid?

为什么是混合动力?

  • It wouldn't be an Implicit Grant Flowaka Client-Side Web Applications Flowbecause there is no redirection to API server too grant access token. (i.e.) "Is it ok for so-and-so to access your data?"

  • It wouldn't be a Resource Owner Password Flowbecause a Client ID and Client Secretare passed along with the request so it's assumed the client app is server-side.

  • 它不会是Implicit Grant Flowaka,Client-Side Web Applications Flow因为没有重定向到 API 服务器也授予访问令牌。(即)“某某人可以访问您的数据吗?”

  • 这不会是Resource Owner Password Flow因为客户端 ID 和客户端密钥与请求一起传递,因此假设客户端应用程序是服务器端。

OK... so what about a little bit of both?

好吧……那么两者都有点怎么样?

What if we used a CRSF token on page load of client-side app, and POST it with user credentials too OAuth 2.0 authentication endpoint to exchange for access token? You would authenticate each subsequent request with the access token and CRSF token after a successful login.

如果我们在客户端应用程序的页面加载上使用 CRSF 令牌,并将其与用户凭据一起发布 OAuth 2.0 身份验证端点以交换访问令牌怎么办?成功登录后,您将使用访问令牌和 CRSF 令牌对每个后续请求进行身份验证。

A good Node.js OAuth 2.0 library I found:

我发现了一个很好的 Node.js OAuth 2.0 库:

https://github.com/ammmir/node-oauth2-provider

https://github.com/ammmir/node-oauth2-provider

Help Me!

帮我!

I can not find a working example of an authentication measure that solves this problem! Point me in the right direction?

我找不到解决此问题的身份验证措施的工作示例!指出我正确的方向?

Ultimately, the goal here is too authenticate a client side app to a REST api using CORS with a local strategy --- i.e. username & password --- even if the convention above isn't possible.

最终,这里的目标也是使用 CORS 和本地策略 --- 即用户名和密码 --- 向 REST api 验证客户端应用程序,即使上述约定是不可能的。

To Accommodate Bounty:

容纳赏金:

This is a client side app, so let's stay trendy.

这是一个客户端应用程序,所以让我们保持时尚。

I'm looking for a working example using the Node.jsOAuth 2.0 seed above for the API/Auth server and a front end framework like Angular.jsor Backbone.jsto make requests.

我正在寻找一个工作示例,使用上面的Node.jsOAuth 2.0 种子作为 API/Auth 服务器和前端框架(如Angular.jsBackbone.js)来发出请求。

The example should match the context described above.

该示例应与上述上下文相匹配。

回答by jandersen

I'm working on an app with a pretty similar architecture though the services are .NET Web API rather than Node and we're using DotNetOpenAuthfor the OAuth provider. Rather than the hybrid approach you're suggesting we're doing the following:

我正在开发一个具有非常相似架构的应用程序,尽管服务是 .NET Web API 而不是 Node,我们使用DotNetOpenAuth作为 OAuth 提供程序。而不是您建议的混合方法,我们正在执行以下操作:

  1. x.com serves up a login page
  2. login page POSTs back credentials to x.com
  3. server side logic at x.com combines client_id and client_secret with the credentials to submit a token request (resource owner password credentials grantthat you've mentioned above) receiving back both a temporary access token and a refresh token
  4. the refresh token is encrypted into a cookie issued by x.com
  5. both the cookie (with encrypted refresh token) and the temporary access token are then sent to the browser
  6. the client app (angular in my case) can now use the access token to hit api.x.com for services (It appears you're well aware of the limitations of CORS... we hacked a version of angular's $resourceto facilitate this but it wasn't pretty since we wanted to use all HTTP verbs and support IE9)
  7. when the access token expires, the client side app can request a new access token from x.com
  8. server-side, x.com decrypts the cookie to get at the refresh token and issues another oauth call for a new access token
  1. x.com 提供登录页面
  2. 登录页面将凭据发回 x.com
  3. x.com 上的服务器端逻辑将 client_id 和 client_secret 与凭据结合以提交令牌请求(您在上面提到的资源所有者密码凭据授予)接收临时访问令牌和刷新令牌
  4. 刷新令牌被加密成 x.com 发布的 cookie
  5. 然后将 cookie(带有加密的刷新令牌)和临时访问令牌发送到浏览器
  6. 客户端应用程序(在我的例子中是 angular)现在可以使用访问令牌来访问 api.x.com 以获得服务(看来你很清楚 CORS 的局限性......我们破解了一个 angular 的$resource版本以方便但这并不漂亮,因为我们想使用所有 HTTP 动词并支持 IE9)
  7. 当访问令牌过期时,客户端应用程序可以从 x.com 请求新的访问令牌
  8. 服务器端,x.com 解密 cookie 以获取刷新令牌并发出另一个 oauth 调用以获取新的访问令牌

This is fairly high-level but hopefully gives you a sense for how to tackle your situation. In my case, and it appears in yours, we didn't want to use session state or a database to store the refresh token but obviously exposing that to the browser introduces security concerns so the encryption of the refresh token is important (among other security considerations) and the use of the cookie eliminates the need for session state or other persistent storage on x.com.

这是相当高水平的,但希望能让您了解如何解决您的情况。在我的情况下,它出现在你的情况下,我们不想使用会话状态或数据库来存储刷新令牌,但显然将其暴露给浏览器会引入安全问题,因此刷新令牌的加密很重要(除其他安全性外)考虑)并且使用 cookie 消除了 x.com 上对会话状态或其他持久存储的需要。

回答by Pablo

I've built this example using Node and PassportJS to show how to authenticate the users with Facebook or Local Strategy. Both sides are on different domains as you described and it requires CORS enabled.

我已经使用 Node 和 PassportJS 构建了这个示例,以展示如何使用 Facebook 或本地策略对用户进行身份验证。正如您所描述的,双方都在不同的域中,并且需要启用 CORS。

GitHub: https://github.com/pablodenadai/Corsnection
Live demo: http://corsnection-client.herokuapp.com/

GitHub:https: //github.com/pablodenadai/Corsnection
现场演示:http: //corsnection-client.herokuapp.com/

回答by unludo

Not an answer running for the prize. Just my 2 cents :)

不是争夺奖品的答案。只有我的 2 美分 :)

On my web server,

在我的网络服务器上,

I do my authentication through a rest call with login/password with basic authentication over https. This call delivers a key to the client (a one page web app).

我通过使用登录名/密码的休息调用进行身份验证,并通过 https 进行基本身份验证。此调用将密钥传递给客户端(一个单页 Web 应用程序)。

Then every subsequent REST call is signed with the key. The server checks that the signature is correct and everything still happen in https.

然后每个后续 REST 调用都使用密钥签名。服务器检查签名是否正确,一切仍然发生在 https 中。

This mechanism is quite used I believe.

我相信这种机制非常有用。

I don't see the issue with cross domain. I have a single source anf if I need something from another source, I'd use JSONP.

我没有看到跨域的问题。我有一个单一的来源,如果我需要来自另一个来源的东西,我会使用 JSONP。

I use nginx as an https->http forwarder.

我使用 nginx 作为 https->http 转发器。

Not sure how it competes with an OAuth2 solution.

不确定它如何与 OAuth2 解决方案竞争。

回答by Kyaw Tun

I very similar idea using vinilla js web app and cross domain authentication to GAE backend or OpenID connect.

我非常相似的想法使用 vinilla js web 应用程序和跨域身份验证到 GAE 后端或 OpenID 连接。

The web app is run on CDN. When click login link, it goes to respective login server and redirect back to the web app (with XSRF security token and HTTPS only cookie). Login server accept cross domain request with credentials. XSRF token has to be set (in header) with every request. cookie is set by the browser. Since it is HTTP only cookie, JS cannot read it. The technique is very secure.

Web 应用程序在 CDN 上运行。单击登录链接时,它会转到相应的登录服务器并重定向回 Web 应用程序(使用 XSRF 安全令牌和仅 HTTPS cookie)。登录服务器接受带有凭据的跨域请求。每个请求都必须设置 XSRF 令牌(在标头中)。cookie 由浏览器设置。由于它是 HTTP only cookie,JS 无法读取它。该技术非常安全。

Once login, you can get secure assess from login server.

登录后,您可以从登录服务器获得安全评估。

For detail description, you can find hereand open source repohere.

有关详细说明,您可以在此处找到并在此处找到开源存储

回答by Milan Jaric

I can't promise that I have time to write working example but I can show you 2 paths :)

我不能保证我有时间编写工作示例,但我可以向您展示 2 条路径:)

The biggest deal is CORS. After you solve that problem it is easy to use $httpservice. So, first and probably easiest may be to configure reverse proxy in x.com webserver which points to api.x.com. I wrote article here

最大的交易是 CORS。解决了这个问题之后,就很容易使用$http服务了。因此,首先也是最简单的方法可能是在指向 api.x.com 的 x.com 网络服务器中配置反向代理。我在这里写了文章

Second approach is better, and created for exactly this purpose, to authorise specific domain to use your resource. It involves a bit of coding in api.x.com so you don't have to change anything in new web applications served in other domains. You simply need to authorise CORS requests in api.x.com service.

第二种方法更好,并且正是为此目的而创建的,以授权特定域使用您的资源。它涉及在 api.x.com 中进行一些编码,因此您不必在其他域中提供的新 Web 应用程序中进行任何更改。您只需要在 api.x.com 服务中授权 CORS 请求。

  • Create table in database where you can manage list of authorised domains
  • Add in that table record "x.com"
  • in api.x.com add request filter/interceptor what ever tech term you use for method which should be invoked after request is handled and add in response Access-Control-Allow-Origin: x.comif request comes from x.com (in other words check in request header refer value match to any value in table above and put that value in Access-Control-Allow-Origin response header).
  • 在数据库中创建表,您可以在其中管理授权域列表
  • 添加该表记录“x.com”
  • 在 api.x.com 中添加请求过滤器/拦截器你使用的技术术语应该在请求被处理后调用,Access-Control-Allow-Origin: x.com如果请求来自 x.com 则添加响应(换句话说,检查请求标头引用值匹配到上表中的任何值并将该值放在 Access-Control-Allow-Origin 响应标头中)。

That is all :) After this if you know how to use $httpor jQuey.ajaxyou will be able to POST/PUT/DELETE/... any request to api.x.com from any authorised domain in just few minutes.

这就是全部:) 在此之后,如果您知道如何使用$httpjQuey.ajax,您将能够在几分钟内 POST/PUT/DELETE/... 从任何授权域向 api.x.com 发出任何请求。