利用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作为身份提供商,并以一个简单的网站作为示例应用。端到端流程如下:

为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图形用户界面,但该界面更新频繁,菜单选项及其位置可能会发生变化。请将这些说明作为参考,并根据当前界面酌情调整。]
- 访问Google APIs信息中心:https://console.developers.google.com/apis/dashboard。打开的页面取决于您之前使用Google APIs的情况。您可能需要创建账号、接受使用条款,并完成本说明中未列出的其他步骤。以下屏幕截图显示了信息中心的左上角。点击Google APIs徽标右侧的文字(如果之前创建过项目,可能会显示项目名称,而不是Project)。选择Create project。

- 创建一个新项目。此处,我们将新项目命名为“NGINX OpenID”。点击“创建”按钮后,可能需要等待几秒钟,才会显示项目已创建的通知。

- 为项目启用Google+ API。该API提供OAuth 2.0身份验证和身份服务。(如果窗口的主区域尚未显示API Manager信息中心,请在屏幕左侧的导航区域中点击“Dashboard”。)启用Google+ API的第一步是点击“ENABLE API”按钮。

- 点击“Google+ API”(位于“Social APIs”部分)。

- 点击“启用”按钮。

- 要为项目创建凭据,请点击屏幕左侧导航区域中的“凭据”,然后点击“创建凭据”按钮。在下拉菜单中选择“OAuth客户端ID”。

- 选择“Web 应用”单选按钮。在“已获授权的 JavaScript 来源”字段中,指定安装 NGINX Plus 的主机 URL,以及在《
listen》指令中作为参数指定的端口号,具体请参阅《为 Web 应用启用 OpenID Connect》(例如,mydomain.example.com:80)。此示例使用 localhost,但您需要输入实际 NGINX Plus 实例的主机名和端口。单击“创建”按钮(可能需要多次单击才能启动创建过程)。
- 此时会弹出“OAuth 客户端”窗口,其中显示客户端ID和客户端密钥。将客户端ID复制到应用中
content属性的<meta name="google-signin-client_id">标记内(替换上方突出显示的client-ID占位符)。无需使用客户端密钥。
- 在主凭据屏幕上,点击OAuth 同意屏幕。输入电子邮件地址和产品名称(其他所有字段均为可选字段)。

返回相关章节,了解如何创建使用这些凭据的示例应用程序
要了解NGINX Plus的原生JWT支持,立即开始30天免费试用,或联系我们。
关于作者

相关博客文章
NGINX Plus R26 正式发布
NGINX Plus R26通过缓存JSON Web密钥集加快JWT验证,并强化TLS握手,从而提升安全性。NGINX JavaScript的新功能包括增强对异步函数的支持,以及实现WebCrypto API。
使用NGINX App Protect DoS保护gRPC应用,抵御严重的DoS攻击
gRPC具备开发人员设计和部署现代应用所需的速度与灵活性,但其开放性也使其极易受到第7层DoS攻击。NGINX App Protect DoS可保护gRPC应用免受此类破坏性攻击。
Ingress Controller 选型指南(第 2 部分):风险与面向未来的规划
了解选择错误的Ingress控制器可能带来的风险,以及如何从关键方面着手,让您的选择更好地适应未来需求。
NGINX Plus R19 正式发布
NGINX Plus R19扩展了监控功能,不仅提供更多指标,还新增了指标分析方式;增加试运行模式,用于测试限速效果;增强键值存储,以支持IP地址范围;并使限速更加动态。
NGINX现已正式加入F5
NGINX现已正式成为F5的一部分。Gus Robertson现任F5 NGINX业务部门负责人。他阐述了两家公司在人才、文化和愿景方面融合的价值,以及双方将如何携手增强NGINX的开源产品和商业产品。
