使用OpenID Connect和NGINX Plus对现有应用的用户进行身份验证

NGINX | 2016年9月07日

利用JWT支持为现有应用提供单点登录

[编辑注:本文介绍如何将NGINX Plus与支持隐式流程的OpenID Connect提供商配合使用,以进行身份验证。文中的信息在技术上是正确的,但由于我们的参考实现已更新,某些操作(例如使用 cron 获取公钥)已不再需要。有关当前实现,请参阅我们的GitHub存储库。

在NGINX Plus R15及更高版本中,还可以将NGINX Plus用作OpenID Connect授权码流程中的依赖方。]

OAuth 2.0极大提升了网站和应用身份验证的灵活性与用户体验。但与其名称所暗示的不同,OAuth 2.0规范对最终用户身份验证的说明很少,也完全没有涉及单点登录(SSO)。这正是OpenID Connect发挥作用之处;它实质上补上了缺失的一环,在OAuth 2.0访问令牌中承载身份信息。

OpenID Connect身份令牌符合JSON Web Token(JWT)规范。JWT(读作“jot”)令牌结构紧凑、易于传递,并提供用于描述身份信息的通用核心架构。JWT的优势在于,它几乎适用于所有身份用例,包括对API客户端进行身份验证,以及为企业应用提供单点登录(SSO)。事实上,许多使用Google Apps的组织可以将Google用作身份提供商,为其企业应用提供SSO。不过,使用OpenID Connect和JWT并不妨碍将其用于现有Web应用的身份验证或为这些应用提供SSO。

NGINX Plus R10及更高版本原生支持JWT,使NGINX Plus能够验证令牌,并将已认证用户的身份信息添加到上游请求中,便于应用使用。本文将演示如何利用NGINX Plus的原生JWT支持为现有应用启用SSO,而无需对应用本身进行任何更改。我们使用Google作为身份提供商,并以一个简单的网站作为示例应用。端到端流程如下:

NGINX Plus使用OAuth 2.0和OpenID Connect验证用户身份,实现基于Google的SSO

为Web应用启用OpenID Connect

我们的示例包含两个组件:NGINX Plus配置和HTML登录页面。

NGINX Plus 配置

用于验证JWT的NGINX Plus配置非常简单。

server {    listen 80;
    root /var/www/public_html;

    location /private/ {
        auth_jwt "Google account" token=$cookie_auth_token;
        auth_jwt_key_file /etc/nginx/google_certs.jwk;
    }
}

The location块指定,所有以/private/开头的URL请求都必须经过身份验证。auth_jwt指令定义了身份验证失败时随401状态码一同返回的身份验证领域,并指定NGINX Plus可从请求中的哪个位置找到JWT。在本例中,NGINX Plus会在名为auth_token的Cookie中查找令牌。默认情况下,NGINX Plus要求客户端通过Bearer Token形式提供JWT,并使用Authorization标头,这在AJAX应用程序和API客户端中很常见。不过,NGINX Plus也可以从其他HTTP标头、查询字符串参数或本例所示的Cookie中获取JWT。

The auth_jwt_key_file指令用于告知NGINX如何验证JWT的签名部分。签名验证可确保JWT由Google签发且此后未被修改。Google会发布其公钥并定期更新。为使密钥集保持最新,请使用cron(8)每小时获取一次,如以下crontab条目示例所示。

0 * * * * wget https://www.googleapis.com/oauth2/v3/certs -O /etc/nginx/google_certs.jwk

基于HTML的登录页面

为使本示例简单明了,我们不会构建完整的应用程序,而是使用以下基本HTML创建登录页面。HTML文件名为/var/www/public_html/index.html(与NGINX Plus配置中定义的root路径一致)。

<html>
<head>
    <meta http-equiv="cache-control" content="no-cache" />
    <meta http-equiv="expires" content="0" />
    <title>NGINX OpenID Connect demo</title>
    <script src="https://apis.google.com/js/platform.js" async defer></script>
    <meta name="google-signin-scope" content="profile email">
    <meta name="google-signin-client_id" content="client-ID.apps.googleusercontent.com"> <script src="/js.cookie.js"></script>
</head>
<body>
    <h2>NGINX OpenID Connect demo</h2>
    <hr/>
    <h3>Login with a Google account then visit the <a href="/private/">private area</a>.</h3>
    <table><tr><td>
    <div class="g-signin2" data-onsuccess="onSignIn" data-theme="dark"></div></td>
    <script>
      function onSignIn(googleUser) {
        var profile = googleUser.getBasicProfile();
        Cookies.set('auth_token', googleUser.getAuthResponse().id_token);
        document.getElementById('google_signout').innerHTML = '<a href="#" onclick="signOut();"><img src="' + profile.getImageUrl() + '" width=32 height=32>Sign out</a>';
      };
      function signOut() {
        var auth2 = gapi.auth2.getAuthInstance();
        auth2.signOut().then(function () {
          Cookies.remove('auth_token');
          document.getElementById('google_signout').innerHTML = '';
        });
      }
    </script>
    <td><div id="google_signout"></div></td>
    </tr></table>
    <hr/>
</body>
</html>

我们已突出显示<head>块中的两个关键依赖项。

  • <meta name="google‑signin‑client_id"> 标记:我们使用 Google OAuth 2.0 JavaScript API 来执行OAuth 2.0最终用户同意和身份验证流程。该API为我们提供登录按钮,并可检测当前是否已登录。为了让Google对我们的网站进行身份验证,需要创建OAuth 2.0客户端ID,并将其作为此标记的content属性值,以替换client-ID占位符。有关创建新OAuth 2.0客户端ID的说明,请参阅本文底部的附录。
  • <script src="/js.cookie.js"> 标记:我们需要一个Cookie解析器,用于从OAuth 2.0访问令牌中提取身份令牌,并创建一个要发送到网站的Cookie。以下代码行可实现此操作:Cookies.set。该代码使用此标记所引入的JavaScript Cookie库。

完成这些配置后,我们便有了一个采用Google登录机制的公开主页,以及一个受NGINX Plus保护的私有区域。请注意,我们没有为私有区域创建任何内容,因此尝试访问该区域时,出现404错误属于正常情况。

延伸阅读

有关高级JWT功能的详细信息,请参阅《使用JWT和NGINX Plus对API客户端进行身份验证》。其中介绍了如何使用从JWT中获取的用户身份信息代理已通过身份验证的请求、记录JWT声明,以及支持多个身份提供商。

要体验NGINX Plus的原生JWT支持,立即开始30天免费试用,或联系我们。

附录:创建 Google OAuth 2.0 客户端 ID

[编辑注:我们已尽力准确呈现本文发布时的Google APIs图形用户界面,但该界面更新频繁,菜单选项及其位置可能会发生变化。请将这些说明作为参考,并根据当前界面酌情调整。]

  1. 访问Google APIs信息中心:https://console.developers.google.com/apis/dashboard。打开的页面取决于您之前使用Google APIs的情况。您可能需要创建账号、接受使用条款,并完成本说明中未列出的其他步骤。以下屏幕截图显示了信息中心的左上角。点击Google APIs徽标右侧的文字(如果之前创建过项目,可能会显示项目名称,而不是Project)。选择Create project。
    创建Google OAuth 2.0客户端ID时,请从API Manager信息中心左上角Google APIs徽标旁的下拉菜单中选择“Create project”。
     
  2. 创建一个新项目。此处,我们将新项目命名为“NGINX OpenID”。点击“创建”按钮后,可能需要等待几秒钟,才会显示项目已创建的通知。
    创建Google OAuth 2.0客户端ID时,请为新项目指定名称。
     
  3. 为项目启用Google+ API。该API提供OAuth 2.0身份验证和身份服务。(如果窗口的主区域尚未显示API Manager信息中心,请在屏幕左侧的导航区域中点击“Dashboard”。)启用Google+ API的第一步是点击“ENABLE API”按钮。
    创建Google OAuth 2.0客户端ID时,在API Manager Dashboard屏幕上点击ENABLE API按钮。
     
  4. 点击“Google+ API”(位于“Social APIs”部分)。
     
  5. 点击“启用”按钮。
     
  6. 要为项目创建凭据,请点击屏幕左侧导航区域中的“凭据”,然后点击“创建凭据”按钮。在下拉菜单中选择“OAuth客户端ID”。
    创建Google OAuth 2.0客户端ID时,选择“OAuth客户端ID”作为要创建的凭据类型。
     
  7. 选择“Web 应用”单选按钮。在“已获授权的 JavaScript 来源”字段中,指定安装 NGINX Plus 的主机 URL,以及在《listen》指令中作为参数指定的端口号,具体请参阅《为 Web 应用启用 OpenID Connect》(例如,mydomain.example.com:80)。此示例使用 localhost,但您需要输入实际 NGINX Plus 实例的主机名和端口。单击“创建”按钮(可能需要多次单击才能启动创建过程)。
     
  8. 此时会弹出“OAuth 客户端”窗口,其中显示客户端ID和客户端密钥。将客户端ID复制到应用中content属性的<meta name="google-signin-client_id">标记内(替换上方突出显示的client-ID占位符)。无需使用客户端密钥。
    成功创建Google OAuth 2.0客户端ID后,该ID会与客户端密钥一起显示在“OAuth客户端”窗口中。
     
  9. 在主凭据屏幕上,点击OAuth 同意屏幕。输入电子邮件地址和产品名称(其他所有字段均为可选字段)。
     

返回相关章节,了解如何创建使用这些凭据的示例应用程序

要了解NGINX Plus的原生JWT支持,立即开始30天免费试用,或联系我们。


分享

关于作者

相关博客文章

NGINX Plus R26 正式发布
NGINX | 2022/02/15

NGINX Plus R26 正式发布

NGINX Plus R26通过缓存JSON Web密钥集加快JWT验证,并强化TLS握手,从而提升安全性。NGINX JavaScript的新功能包括增强对异步函数的支持,以及实现WebCrypto API。

使用NGINX App Protect DoS保护gRPC应用,抵御严重的DoS攻击
NGINX | 2022/02/10

使用NGINX App Protect DoS保护gRPC应用,抵御严重的DoS攻击

gRPC具备开发人员设计和部署现代应用所需的速度与灵活性,但其开放性也使其极易受到第7层DoS攻击。NGINX App Protect DoS可保护gRPC应用免受此类破坏性攻击。

Ingress Controller 选型指南(第 2 部分):风险与面向未来的规划
NGINX | 2021/09/13

Ingress Controller 选型指南(第 2 部分):风险与面向未来的规划

了解选择错误的Ingress控制器可能带来的风险,以及如何从关键方面着手,让您的选择更好地适应未来需求。

NGINX Plus R19 正式发布
NGINX | 2019/09/03

NGINX Plus R19 正式发布

NGINX Plus R19扩展了监控功能,不仅提供更多指标,还新增了指标分析方式;增加试运行模式,用于测试限速效果;增强键值存储,以支持IP地址范围;并使限速更加动态。

NGINX现已正式加入F5
NGINX | 2019/05/09

NGINX现已正式加入F5

NGINX现已正式成为F5的一部分。Gus Robertson现任F5 NGINX业务部门负责人。他阐述了两家公司在人才、文化和愿景方面融合的价值,以及双方将如何携手增强NGINX的开源产品和商业产品。

使用NGINX和NGINX Plus实现高性能缓存
NGINX | 2016/08/24

使用NGINX和NGINX Plus实现高性能缓存

我将介绍NGINX在内容缓存和性能方面的工作原理,并分享一些控制NGINX内容缓存方式的技巧。