jjzjj

javascript - 公共(public)第一方客户端的正确 OAuth2 流程

coder 2024-05-09 原文

我是 stack overflow 的常客,但这是我的第一个问题。

我正在使用 OAuth2 规范开发授权服务器。我只是被困在如何在使用密码流的同时确保第一方客户端的真实性上。我阅读了很多论坛,这就是我得到的:

  1. Javascript 单页客户端

    Alex Bilbie 的这篇博文,他指出,为了避免 client_secret 问题,我们应该:

    It’s simple; proxy all of your API calls via a thin server side component. This component (let’s just call it a proxy from here on) will authenticate ajax requests from the user’s session. The access and refresh tokens can be stored in an encrypted form in a cookie which only the proxy can decrypt. The application client credentials will also be hardcoded into the proxy so they’re not publicly accessible either.

    但是现在这个代理可以被冒充我的人访问 Angular 应用程序。然后我看到了 Andy 的这篇博文 外野手:How Secure is the OAuth2 Resourc Owner Password Flow for Single Page Apps .他基本上说要依靠 CORS 来 避免冒充 JS 客户端。

    使用这两种方法来保护我的 JS 应用程序是个好主意吗?

  2. 本地应用(桌面和移动)

    在移动应用的情况下,我只找到授权的情况 代码和隐式流程。这不是我想要的,因为重定向 会损害用户体验。所以我对此的看法是:

    我将使用 ROP 流程,然后使用一个 client_id 为这个特定的安装生成并附上它 到用户帐户,接收 access_tokenclient_secret 作为响应。由此发出的任何其他 token 请求 客户端必须携带此凭据(因为 client_id 是特定的 对于安装,我将能够检查此客户端是否 已经认证)。这样,如果有人使用任何凭据 冒充客户,甚至注册一个假客户,我可以采取 撤销用户和客户端访问权限的措施。

我知道这可能是想多了,我也知道有些事情并不能避免任何事情。我只是觉得尽我所能保护我的 API 是我的工作。

我非常感谢您对此问题的看法!我真的是多虑了吗?我应该只使用“公共(public)客户”的概念并继续吗?

谢谢大家,祝编码愉快!

最佳答案

首先,这个问题不是一个常见的优先级,因为大多数应用程序都是先用网站开发的,然后再用 API 开发的。这可能是原因,因为没有人知道如何使用 oauth2 处理第一批客户,因为每个人都开发了其他方法来做到这一点,而只需要 oauth2 来授予用户对第三方应用程序的访问权限。

即使您仅为第一个客户端应用程序开发了 oauth2 授权服务器(考虑单一身份验证机制而不是开发多个),您也应该尝试开发授权代码或隐式授权类型。您会意识到您需要一种方法来检查实际登录的用户

两种常用的方法是:

  • 用户 session (基于 Cookie)
  • 来自 localStorage 的用户访问(基于 javascript)

无论哪种方式,您都需要检查您的应用程序安全性,用户 session 易受 CSRF 攻击,localStorage 易受 XSS 攻击。有很多关于如何保护您的网站免受任何一种攻击的文章,所以我不会在这里提出任何建议,您只需要知道它们的存在即可。

既然您选择了身份验证方法,我们就可以开始考虑:

Javascript 单页应用

  1. 代理
    在我看来,拥有一个过滤所有请求的代理就像有一扇总是插着 key 的门。建门也没用。 但是,对于基于 session 的身份验证,这是唯一的方法。在 Rest API 上允许 session 身份验证会导致 CSRF 安全问题,因此您需要有一个代理层来获取用户 session 、从 session 中检索访问 token 并向 Rest API 添加 Authorization 标题。

  2. CORS
    使用此方法,您需要将用户访问 token 存储在 localStorage 中,因为 token 是直接从 Js 客户端检索的。
    使用 CORS,您可以确定其他网站无法从浏览器向您的 Rest API 发出请求。但是您的第一个客户端需要公开(即:它没有 client_secret)。

native 应用程序(桌面和移动)

在我的第一个应用程序中,我尝试使用您建议的相同机制来保护身份验证流程。然而,这种机制要求您以唯一的方式识别每个用户客户端。这在 iOS 中是不可能的 privacy reasons并且有可能在未来的 Android 版本中被拒绝。因此,您应该依赖公共(public)客户端并在您的 native 应用程序代码中仅添加 client_id

也就是说你的native app client/你的js client可以非个性化?
是的,并且无法通过 oAuth2 资源所有者密码凭据授予类型来防止这种情况

主要是因为oAuth2不是为了鉴权,只是为了第三方授权,并且添加了grant type只是为了特定的第三方应用可信到足以直接使用用户密码。你可以阅读更多关于这个论点的信息 herehere .

最后

您仍然需要一种方法来授权您的用户,我认为使用 oAuth2 可以实现的最佳效果是 Auth0做过。 本质上,此 SaaS 使用 oAuth2 服务器 + OpenID 连接管理您的用户,因此您始终像管理第三方应用程序一样管理您的用户,并且一切正常。

的确,你可以在this page上看到对于移动应用程序,他们建议使用基于浏览器的登录表单,因为反编译您的应用程序的每个人都可以将原生表单非个性化,但如果您将其包装到授权代码流中,它就可以正常工作。

关于javascript - 公共(public)第一方客户端的正确 OAuth2 流程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37200642/

有关javascript - 公共(public)第一方客户端的正确 OAuth2 流程的更多相关文章

  1. ruby - Sinatra set cache_control to static files in public folder编译错误 - 2

    我不知道为什么,但是当我设置这个设置时它无法编译设置:static_cache_control,[:public,:max_age=>300]这是我得到的syntaxerror,unexpectedtASSOC,expecting']'(SyntaxError)set:static_cache_control,[:public,:max_age=>300]^我只想将“过期”header设置为css、javaascript和图像文件。谢谢。 最佳答案 我猜您使用的是Ruby1.8.7。Sinatra文档中显示的语法似乎是在Ruby1.

  2. ruby - 在 Ruby 中创建按公共(public)键值分组的新哈希 - 2

    假设我有一个在Ruby中看起来像这样的哈希:{:ie0=>"Hi",:ex0=>"Hey",:eg0=>"Howdy",:ie1=>"Hello",:ex1=>"Greetings",:eg1=>"Goodday"}有什么好的方法可以将它变成如下内容:{"0"=>{"ie"=>"Hi","ex"=>"Hey","eg"=>"Howdy"},"1"=>{"ie"=>"Hello","ex"=>"Greetings","eg"=>"Goodday"}} 最佳答案 您要求一个好的方法来做到这一点,所以答案是:一种您或同事可以在六个月后理解

  3. ruby - "public/protected/private"方法是如何实现的,我该如何模拟它? - 2

    在ruby中,你可以这样做:classThingpublicdeff1puts"f1"endprivatedeff2puts"f2"endpublicdeff3puts"f3"endprivatedeff4puts"f4"endend现在f1和f3是公共(public)的,f2和f4是私有(private)的。内部发生了什么,允许您调用一个类方法,然后更改方法定义?我怎样才能实现相同的功能(表面上是创建我自己的java之类的注释)例如...classThingfundeff1puts"hey"endnotfundeff2puts"hey"endendfun和notfun将更改以下函数定

  4. ruby-on-rails - 使用 javascript 更改数据方法不会更改 ajax 调用用户的什么方法? - 2

    我遇到了一个非常奇怪的问题,我很难解决。在我看来,我有一个与data-remote="true"和data-method="delete"的链接。当我单击该链接时,我可以看到对我的Rails服务器的DELETE请求。返回的JS代码会更改此链接的属性,其中包括href和data-method。再次单击此链接后,我的服务器收到了对新href的请求,但使用的是旧的data-method,即使我已将其从DELETE到POST(它仍然发送一个DELETE请求)。但是,如果我刷新页面,HTML与"new"HTML相同(随返回的JS发生变化),但它实际上发送了正确的请求类型。这就是这个问题令我困惑的

  5. ruby - private、protected 和 public 的范围 - 2

    在Ruby类定义中,private关键字在以下场景中的作用域是什么:classFoodefbar_publicputs"public"endprivatedefbar_privateputs"private"enddefbar_public_2puts"anotherpublic"endendprivate是否只作用于bar_private?还是在bar_public_2上? 最佳答案 在您的例子中,bar_private和bar_public_2都是私有(private)的。那是因为这两种方法都在private关键字的“范围内”。

  6. ruby - 在 Ruby 模块中定义公共(public)方法? - 2

    我一定是犯了n00b错误。我编写了以下Ruby代码:moduleFoodefbar(number)returnnumber.to_s()endendputsFoo.bar(1)测试.rb:6:in':undefinedmethodbar'forFoo:Module(NoMethodError)我想在名为Foo.bar的模块上定义一个方法。但是,当我尝试运行代码时,出现未定义方法错误。我做错了什么? 最佳答案 你可以这样做:moduleFoodefself.bar(number)number.to_sendendputsFoo.bar

  7. ruby - 在 TCPServer (Ruby) 中,我如何从客户端获取 IP/MAC? - 2

    我想在Ruby的TCPServer中获取客户端的IP地址。以及(如果可能的话)MAC地址。例如,Ruby中的时间服务器,请参阅评论。tcpserver=TCPServer.new("",80)iftcpserverputs"Listening"loopdosocket=tcpserver.acceptifsocketThread.newdoputs"Connectedfrom"+#HERE!HowcanigettheIPAddressfromtheclient?socket.write(Time.now.to_s)socket.closeendendendend非常感谢!

  8. ruby-on-rails - Rails 两条腿的 OAuth 提供商? - 2

    我有一个Rails2.3.5应用程序,其中包含我希望保护的API。没有用户-它是一个应用到应用风格的网络服务(更像是亚马逊服务而不是facebook),所以我想使用两条腿的OAuth方法来实现它。我一直在尝试使用oauth-plugin服务器实现作为开始:http://github.com/pelle/oauth-plugin...但它的构建需要三足(网络重定向流)oauth。在我深入研究对其进行更改以支持两条腿之前,我想看看是否有更简单的方法,或者是否有人有更好的方法让Rails应用程序实现成为两条腿的OAuth提供程序。 最佳答案

  9. ruby - 在 Mechanize 中使用 JavaScript 单击链接 - 2

    我有这个:AccountSummary我想单击该链接,但在使用link_to时出现错误。我试过:bot.click(page.link_with(:href=>/menu_home/))bot.click(page.link_with(:class=>'top_level_active'))bot.click(page.link_with(:href=>/AccountSummary/))我得到的错误是:NoMethodError:nil:NilClass的未定义方法“[]” 最佳答案 那是一个javascript链接。Mechan

  10. ruby - 如何使用 omniauth/oauth 对每秒登录数进行基准测试? ( ruby +rspec) - 2

    我想用一个(自己的)omniauth提供商来衡量每秒可以登录多少次。我需要了解此omniauth/oauth请求的性能如何,以及此身份验证是否具有可扩展性?到目前为止我得到了什么:defperformance_auth(user_count=10)bm=Benchmark.realtimedouser_count.timesdo|n|forkdoclick_on'Logout'omniauth_config_mock(:provider=>"foo",:uid=>n,:email=>"foo#{n}@example.net")visit"/account/auth/foo/"enden

随机推荐