如何在 Javascript 中实现安全的 OAuth2 消费?

     2023-03-04     141

关键词:

【中文标题】如何在 Javascript 中实现安全的 OAuth2 消费?【英文标题】:How do I implement secure OAuth2 consumption in Javascript? 【发布时间】:2012-07-11 12:40:38 【问题描述】:

我正在用 PHP 设计一个将使用 OAuth2.0 的 API。我的最终目标是用 javascript(使用 AngularJS)构建一个直接访问这个 API 的前端应用程序。我知道传统上没有办法保护 javascript 中的事务,因此直接访问 API 是不可行的。前端需要与服务器代码通信,而服务器代码又直接与 API 通信。但是,在研究 OAuth2 时,似乎用户代理流程旨在帮助解决这种情况。

我需要帮助的是在 javascript 中实现 OAuth2 用户代理流程(特别是 AngularJS,如果可能的话,因为这是我在前端使用的)。我还没有找到任何可以做到这一点的示例或教程。我真的不知道从哪里开始,也不想阅读整个 OAuth2 规范,至少没有看到我将要做什么的例子。因此,任何示例、教程、链接等都将不胜感激。

【问题讨论】:

通过关于 SO 的相关问题,我发现这个 JS 库似乎可以简化和处理我正在尝试做的事情。 github.com/andreassolberg/jso 它似乎很小且未使用。另外,它并不能完全解决我的问题。 你发现了吗? @DavidMyers 您在执行此 Javascript 时是否收到了 CORS 错误。你是怎么解决的 【参考方案1】:

Implicit Grant flow(您称为 User-Agent 流)正是要走的路:

隐式授权是一种简化的授权代码流,针对使用 JavaScript 等脚本语言在浏览器中实现的客户端进行了优化。

要了解流程,Google 的 client-side applications 文档是一个非常好的起点。请注意,他们建议您采取额外的令牌验证步骤以避免confused deputy problems。

这是使用 Soundcloud API 和 jQuery 的流程的简短示例实现,取自 this answer:

<script type="text/javascript" charset="utf-8">
  $(function () 
    var extractToken = function(hash) 
      var match = hash.match(/access_token=([\w-]+)/);
      return !!match && match[1];
    ;

    var CLIENT_ID = YOUR_CLIENT_ID;
    var AUTHORIZATION_ENDPOINT = "https://soundcloud.com/connect";
    var RESOURCE_ENDPOINT = "https://api.soundcloud.com/me";

    var token = extractToken(document.location.hash);
    if (token) 
      $('div.authenticated').show();

      $('span.token').text(token);

      $.ajax(
          url: RESOURCE_ENDPOINT
        , beforeSend: function (xhr) 
            xhr.setRequestHeader('Authorization', "OAuth " + token);
            xhr.setRequestHeader('Accept',        "application/json");
          
        , success: function (response) 
            var container = $('span.user');
            if (response) 
              container.text(response.username);
             else 
              container.text("An error occurred.");
            
          
      );
     else 
      $('div.authenticate').show();

      var authUrl = AUTHORIZATION_ENDPOINT + 
        "?response_type=token" +
        "&client_id="    + clientId +
        "&redirect_uri=" + window.location;

      $("a.connect").attr("href", authUrl);
    
  );
</script>
<style>
  .hidden 
    display: none;
  
</style>

<div class="authenticate hidden">
  <a class="connect" href="">Connect</a>
</div>

<div class="authenticated hidden">
  <p>
    You are using token
    <span class="token">[no token]</span>.
  </p>

  <p>
    Your SoundCloud username is
    <span class="user">[no username]</span>.
  </p>
</div>

关于使用 AngularJS 发送 XMLHttpRequests(ajax() 函数在 jQuery 中的作用),请参阅他们的 $http service 文档。

如果您想保留状态,在将用户发送到授权端点时,请查看state 参数。

【讨论】:

要使用最新的 SoundCloud api,请将正则表达式更改为 /access_token=([\w-]+)/。他们的标记现在包括破折号字符。 谢谢,我编辑了答案。可能还允许使用其他字符,但我不确定这是否记录在任何地方。 @Ben 隐式和身份验证代码授予的优点之一是客户端应用程序(不管是第一方还是第三方)不必担心存储纯文本凭据用户。这是典型的权衡安全性可用性。 @Ben 好吧,您冒着某些恶意客户端使用您的客户端凭据来欺骗用户的风险。取决于您的用例是否重要。您可以在OAuth 2 Threat Model docs 中找到一些其他注意事项。 不应该是xhr.setRequestHeader('Authorization', "Bearer " + token)吗?【参考方案2】:

有一个使用Authorization Code Grant 方法从 OAuth 服务器获取令牌的示例。我用jQuery($)做了一些操作。

首先,将用户重定向到授权页面。

var authServerUri = "http://your-aouth2-server.com/authorize",
authParams = 
  response_type: "code",
  client_id: this.model.get("clientId"),
  redirect_uri: this.model.get("redirectUri"),
  scope: this.model.get("scope"),
  state: this.model.get("state")
;

// Redirect to Authorization page.
var replacementUri = authServerUri + "?" + $.param(authParams);
window.location.replace(replacementUri);

当一个人通过授权获得令牌时:

var searchQueryString = window.location.search;
if ( searchQueryString.charAt(0) === "?") 
  searchQueryString = searchQueryString.substring(1);

var searchParameters = $.deparam.fragment(searchQueryString);

if ( "code" in searchParameters) 
  // TODO: construct a call like in previous step using $.ajax() to get token.

您可以使用 jQuery 或纯 XMLHttpRequest 以相同的方式实现 Resource Owner Password Credentials Grant,并且不要进行任何重定向 - 因为在每次重定向时,您都会失去应用程序的状态。

对我来说,我使用 HTML5 本地存储来保存不太可能构成安全威胁的数据的应用程序状态。

【讨论】:

在这种情况下,使用 授权码 流程不会比 隐式授权 流程带来额外的好处。此外,如果 API 支持更多(隐藏秘密)和更少(公开秘密)受信任客户端的不同授权流程,则服务器可以区分它们并执行例如额外的检查或限制范围。此外,在这种情况下不应使用 资源所有者密码凭证 流程,因为资源所有者不能从第三方网站获得 high degree of trust 到 JS 客户端代码。 你指的是哪个重定向?授权端点的那个?该重定向也是 implicit grant 流程的一部分。 这是个坏主意。如果您重视用户和您自己的安全,则永远不应在移动设备或客户端应用程序中使用授权授权。使用此系统,您必须将 OAuth2 客户端密码存储在应用程序中黑客可以轻松找到的位置(例如,在源代码中)。如果您要在请求中包含刷新令牌,那么您可能会将用户数据的基本永久密钥交给任何只有少量技能的黑客。 @MichaelOryl 根据规范,您不需要为密码授予提供客户端密码。您的 oauth 服务器应使用列入白名单的 URL 保护客户端,以防止非法使用客户端。 +1,因为最近记录了客户端代码的最佳实践:tools.ietf.org/html/…

如何在javascript中实现区域/代码折叠

】如何在javascript中实现区域/代码折叠【英文标题】:howtoimplementregions/codecollapseinjavascript【发布时间】:2010-12-2715:45:11【问题描述】:如何在VisualStudio中为JavaScript实现区域(也称为代码折叠)?如果javascript中有数百行,那么在v... 查看详情

如何在火花聚合函数中实现scala类型安全

】如何在火花聚合函数中实现scala类型安全【英文标题】:Howtoimplementscalatypesafetyinsidesparkaggregationfunction【发布时间】:2021-09-1322:34:45【问题描述】:如何对agg函数中聚合的值实现类型安全?我的目标是在运行前进行类型检查。$&... 查看详情

java示例代码_如何在Java中实现安全的静态登录凭据系统

java示例代码_如何在Java中实现安全的静态登录凭据系统 查看详情

如何在 C# 中实现 Base64 URL 安全编码?

】如何在C#中实现Base64URL安全编码?【英文标题】:HowtoachieveBase64URLsafeencodinginC#?【发布时间】:2014-12-0819:52:09【问题描述】:我想在C#中实现Base64URL安全编码。在Java中,我们有一个通用的Codec库,它为我提供了一个URL安全编码字... 查看详情

如何在 Javascript 中实现 Haskell 的 FRP Behavior 类型?

】如何在Javascript中实现Haskell的FRPBehavior类型?【英文标题】:HowtoimplementHaskell\'sFRPBehaviortypeinJavascript?【发布时间】:2017-07-1111:10:15【问题描述】:我想了解Haskell中函数式反应式编程的原意,以及它与FRP在Javascript中的实际应用... 查看详情

如何在javascript中实现分层多级数据表?

】如何在javascript中实现分层多级数据表?【英文标题】:HowtoimplementhierarchicalmultileveldatatableinjavaScript?【发布时间】:2019-02-0123:40:40【问题描述】:我在不使用任何插件或库的情况下实现多级数据表。我想基于javaScript、JQuery或ang... 查看详情

如何在 JavaScript/jQuery 中实现重载?

】如何在JavaScript/jQuery中实现重载?【英文标题】:HowcanimplementoverloadinginJavaScript/jQuery?【发布时间】:2011-09-2119:19:36【问题描述】:我正在尝试调用具有相同签名的函数。示例:有两个同名函数:<script>varobj1,obj2,obj3,obj4,obj5;... 查看详情

如何在 Wordpress 中实现 javascript

】如何在Wordpress中实现javascript【英文标题】:HowtoimplementjavascriptintoWordpress【发布时间】:2015-04-0915:44:20【问题描述】:我在理解如何将javascript放入wordpress主题时遇到了一些麻烦。我知道我必须保存这个javascript:http://ajax.googleap... 查看详情

如何在 angularjs 应用程序中实现安全(!)身份验证系统?

】如何在angularjs应用程序中实现安全(!)身份验证系统?【英文标题】:HowtoachieveaSafe(!)authenticationsysteminanangularjsapp?【发布时间】:2013-01-2507:52:29【问题描述】:我是angularjs新手...我阅读了文档,并完成了教程;我自己也尝试... 查看详情

如何在 javascript 中实现 Random.nextDouble()?

】如何在javascript中实现Random.nextDouble()?【英文标题】:HowtoimplementRandom.nextDouble()injavascript?【发布时间】:2019-02-2721:36:57【问题描述】:我正在使用Math.floor((Math.random()*max-min)+min)生成随机数,这个函数和random.nextDouble()有什么区... 查看详情

如何在 Swift 中实现线程安全的 HashTable (PhoneBook) 数据结构?

】如何在Swift中实现线程安全的HashTable(PhoneBook)数据结构?【英文标题】:HowtoimplementaThreadSafeHashTable(PhoneBook)DataStructureinSwift?【发布时间】:2018-08-1214:32:48【问题描述】:我正在尝试实现一个线程安全的电话簿对象。电话簿应该... 查看详情

如何在我的项目中实现 Grails 的 Shiro 安全性

】如何在我的项目中实现Grails的Shiro安全性【英文标题】:howtoimplementShiroSecurityofGrailsinmyProject【发布时间】:2011-08-1411:55:53【问题描述】:我是Grails的新手,使用了一些Shiro安全性。我创建了一个带有登录页面的小网站,如果登... 查看详情

如何在 Struts 1 中实现 Spring 安全性(不在 struts 2 中)

】如何在Struts1中实现Spring安全性(不在struts2中)【英文标题】:HowtoimplementSpringsecurityinStruts1(notinstruts2)【发布时间】:2016-07-0501:30:41【问题描述】:我正在开发企业级Web应用程序,其中安全性应该是一流的。那么,有人可以建... 查看详情

如何在微服务架构中实现基于角色的安全性

】如何在微服务架构中实现基于角色的安全性【英文标题】:howtoimplementrole-basedsecurityinmicroservicesarchitecture[closed]【发布时间】:2020-05-0406:45:32【问题描述】:我有一个带有4个微服务、eureka服务器和一个集中式API网关的spring-boot... 查看详情

如何在 Flutter 中实现音频流应用和安全存储

】如何在Flutter中实现音频流应用和安全存储【英文标题】:Howtoimplementaudiostreamingappandsecurestorageinflutter【发布时间】:2019-11-0603:57:38【问题描述】:我现在要使用颤振https://play.google.com/store/apps/details?id=deezer.android.app构建像deezer... 查看详情

如何在用于编辑 HTML 的 Javascript 组件中实现视图模型分离?

】如何在用于编辑HTML的Javascript组件中实现视图模型分离?【英文标题】:HowcanIachieveview-modelseparationinaJavascriptcomponentforeditingHTML?【发布时间】:2015-09-2600:27:41【问题描述】:我需要为特定的HTML子集构建一个浏览器内WYSI(或多或... 查看详情

如何在飞镖中实现具有异步初始化和空安全性的单例?

】如何在飞镖中实现具有异步初始化和空安全性的单例?【英文标题】:Howtoimplementasingletonwithasyncinitialisationandnullsafetyindart?【发布时间】:2022-01-2402:40:02【问题描述】:我需要一个用于共享首选项的单例,它具有异步初始化但... 查看详情

如何在 html/javascript 中实现登录弹出窗口

】如何在html/javascript中实现登录弹出窗口【英文标题】:Howtoimplementloginpopupinhtml/javascript【发布时间】:2014-01-0919:43:22【问题描述】:基本上,我想创建一个登录弹出窗口,就像许多路由器必须访问设置页面一样:是否可以在html... 查看详情