【51CTO.com快译】作为开发人员,您一定听说过OAuth 2.0和OpenID Connect(OIDC)吧?它们是用于向Web应用程序添加身份验证和授权的两款强大工具。
本文将向您展示如何使用Okta的新型内联钩子(请参见:https://developer.okta.com/docs/reference/api/inline-hooks/)将信息传递到那些通过OIDC和OAuth获得的令牌中。
首先,您将在Okta中设置OIDC应用程序,以查看返回的令牌类型。然后,您将配置一个Spring Boot API应用。通过各种API端点,您可以向Okta注册令牌钩子,并服务于Okta的令牌patch请求。在操作完成的时候,由于注册了钩子,您会发现有效载荷中的令牌。
在和本文一起动手实践之前,请您事先设置好以下内容:
- 通过https://developer.okta.com/signup/创建一个免费的Okta开发者org。
- 安装HTTPie(https://httpie.org/),这是curl的替代品,以用来与API端点进行交互。
- 安装ngrok(https://ngrok.com/),这是一个允许互联网访问本地运行的服务器应用。
- 可选:在https://signup.heroku.com/处创建一个免费的Heroku帐户。
下面,让我们再来了解一下OIDC和OAuth的相关概念。
使用OAuth 2.0进行委托授权
让我们假想一个场景:诸如Yelp(译者注:美国最大的点评网站)之类的客户端应用从诸如Google之类的认证服务中请求访问令牌。您作为资源所有者使用自己的凭据登录Google,并将您的同意授予Yelp,以便其仅访问自己的联系人。因此,Yelp拥有了访问令牌,可以通过Google的Contacts API请求资源服务器,以获取您的联系人信息。在此过程中,Yelp永远不会看到您的密码,也永远不会访问超出您同意范围之外的内容。并且,您可以随时撤回自己的同意。
使用OpenID Connect进行身份识别
在这个同意和授权环节中,您可以注意到它只缺少一样东西:身份。我们需要引入新的令牌:身份令牌,通过在OAuth 2.0之上的一层--OpenID Connect(OIDC),来验证用户的身份信息,并且以JWT(https://developer.okta.com/docs/api/resources/oidc#access-token)格式被编码到经由密码签名的令牌之中。这样既保证了互操作性,又实现了单点登录(Single Sign On)。
OAuth、以及OIDC扩展使用各种已定义的流(Flows)来管理客户端应用、认证服务器、以及资源服务器之间的交互。如下面的流程所示,我们将重点关注浏览器中的认证代码流(Authorization Code Flow):
- 为了访问您的联系人,Yelp通过一个按钮来链接到您的Google通讯录上。
- 在单击该按钮后,您将被重定向到Google处,以使用自己的用户名和密码登录。
- Google通过显示告知您Yelp希望以只读的方式访问您的联系人。
- 一旦您点击同意,Google就会通过浏览器使用临时代码(称为授权代码)重定向回Yelp。
- Yelp使用该代码与Google交换访问令牌。
- 在完成所有的代码验证之后,Google会向Yelp颁发功能有限(仅对您的联系人有只读的访问权限)的访问令牌。
- Yelp将访问令牌提供给Google Contacts API。
- Google Contacts API验证该令牌,如果Yelp的请求与令牌标识的功能相匹配,您的联系人列表则会被返回给Yelp。
为OIDC和OAuth 2.0设置Okta Org
下面,您将在Okta中创建一个OpenID Connect应用。
在登录到Okta org后,您可以根据顶层菜单导航至“应用程序”,单击“添加应用”,单击标签为Web的第三个框,然后单击下一步。
最后单击完成。
在Heroku上的OIDC
为了执行各种可用的流程,我创建了一个OIDC playground应用。
在登录到https://okta-oidc-fun.herokuapp.com后,您会看到一个带有表单和一些切换按钮的页面。它默认指向的是我的Okta org。当然,您可以通过如下表格将其更改为自己的Okta org。
通过向下滚动并单击链接,您可以启动一个新选项卡,并在其中向Okta org进行身份验证。然后,您将会被重定向回ID令牌和访问令牌的位置。而通过单击“验证ID令牌”,您将可以看到有效载荷已经被编码到了该令牌之中。
至此,您已经了解了Okta中的OpenID Connect应用是如何生成各种令牌的。下面,我们将讨论如何创建一个将自定义声明添加到ID令牌的钩子。由于是发生在对ID令牌进行签名之前,因此您仍然可以安全地对密码签名进行验证。
设置Favorite Beers API
请从GitHub上获取本例的源代码--https://github.com/oktadeveloper/okta-token-hooks-example。
这是一个Spring Boot类型的应用,它使用Okta Spring Boot Starter,来轻松与OpenID Connect和OAuth 2.0相集成。它使用H2(https://www.h2database.com/html/main.html)内存嵌入式数据库和Spring Data JPA(https://spring.io/projects/spring-data-jpa)进行简单的对象关系映射,以及Lombok(https://projectlombok.org/)项目。该应用程序指向您的Favorite Beers API,以及一个用于处理Okta传入的钩子请求,并返回ID令牌。
在src/main/resources文件夹中,您将看到application.sample.yml文件。您可以通过复制,由它在同一文件夹中产生application.yml文件。接着根据上述提到的设置,自定义application.yml文件的内容,其中包括:issuer、clientId和clientSecret的值。同时,您也可以将id和password值更改为任何其他值。完成这些设置之后,您可以如下命令运行应用程序:
注意:您需要Java 11或更高的版本,才能运行该示例。如果您使用的是Mac,则建议您使用SDKMAN(https://sdkman.io/),来管理Java版本。
操作Beer应用
在应用启动之后,您将看到如下输出,它表明H2内存数据库里已填充了“啤酒”。
现在,您可以使用Beers API来添加自己喜欢的啤酒。不过,所有API端点都受到了OIDC的保护。请执行如下命令,将啤酒添加到收藏夹列表之中:
如果一切顺利,您将得到如下响应:
至此,您已经为该应用程序都创建了一个新的啤酒条目,并将其添加到了自己的收藏夹列表中。
注意:由于该应用程序使用的是内存数据库,因此如果重新启动该应用的话,则需要使用此API重新添加自己喜爱的啤酒。
下面,我们将设置一个内联钩子,将beers声明添加到自己的ID令牌中。
从ID令牌中获取喜爱的啤酒
为了利用钩子来处理API,Okta需要能够通过公共互联网来对其进行调用。在现实生活中,您可以将应用程序部署在某个地方并进行设置,以方便Okta与之交互。而在此出于演示目的,我们将使用ngrok(https://ngrok.com/)服务,来发送一个唯一的、可公共寻址的域,以连接到本地运行的Spring Boot应用上。请在单独的终端上运行如下命令:
您将看到如下输出:
请复制其https链接(例如:我所看到的是https://e3fc9a95.ngrok.io),以备后续使用。
设置Okta内联钩子
至此,可公开访问的Spring Boot应用已设置就绪,并可接收Okta的钩子请求了。但是,我们的Okta org尚需进行如下准备:
首先,您需要向Okta注册内联令牌钩子。在Okta org的管理控制台中,请依次进入工作流->内联钩子,单击:添加内联钩子->令牌。请在对应的表单中输入如下内容,并点击“保存”:
其中,Authentication field是Okta用来向钩子提供身份验证的标头。而Authentication secret则是在授权标头中发送的值。
注意:请在application.yml文件中找到身份验证的密钥值。如果钩子ID和密码值发生了改变,那么您需要重新计算基本的身份验证字符串,并将该值反映在上面的设置中。
至此,我们已在自己的Okta org中创建了钩子。如下图所示,Spring Boot应用是通过WebSecurityConfiguration.java在钩子的端点上启用基本身份验证的:
基本身份验证被用于/api/hooks/**端点上,而OAuth 2.0则用于其他所有内容。
令牌转换内联钩子的剖析
在配置授权服务器使用钩子之前,让我们先看一下代码的核心。如下代码使用HooksController的方法,可以让ID令牌用您最喜欢的啤酒列表进行patch。
TokenHookRequest的类(class)利用Lombok和一些默认的初始化,来确保您不会收到NullPointerException。
Okta会向控制器发送许多令牌钩子的请求。在此,我们仅针对需要的内容使用@JsonIgnoreProperties(ignoreUnknown = true)注释。如您想了解完整的JSON请求示例,请参见--https://developer.okta.com/docs/reference/token-hook/#sample-json-payload-of-a-request。
通过使用请求中的login值,该代码将进行数据库查找,以检索与关联登录的Person。此处Person的记录是我们在将其添加到喜爱啤酒列表时被创建的。
同时,该代码将设置TokenHookResponse,以便通过命令列表来patch ID令牌、并访问aoken。其中,最关键的一行代码是:
它将啤酒名称列表添加到了beers声明所附带的回复之中。如下便是JSON响应:
而最后一步则是:配置您的授权服务器,以使用该钩子。
将啤酒添加进您的ID令牌
请在顶层菜单中依次点击API->授权服务器->默认->访问策略,向下滚动并点击“默认策略规则”旁的铅笔图标。接着您可以从“使用该内联钩子(Use this inline hook)菜单中,选择“Beers Hook”,并点击“更新规则”。
只要您在浏览器中输入localhost:4040,便可看到ngrok的监视界面。
如果回到前面的OIDC playground,您可以关闭带有ID令牌和访问令牌的结果标签。通过再次点击playground上的链接,以及“验证ID令牌”按钮,您将能够看到beers声明、以及已被添加到收藏夹中的任何啤酒。
通过切换回ngrok监视选项卡,您可以看到Okta的请求和Spring Boot应用的响应。
总结
Okta Spring Boot Starter能够使您通过几行代码、以及三个配置属性,将Spring Boot应用与Okta相集成。它不仅能够让Okta的OpenID Connect服务符合相关标准,而且还能为您提供全面的单点登录体验。也就是说,同一用户可以访问许多不同的OIDC应用,而每一个应用都拥有自己的一套要求和配置。最后,请记住:OIDC不能够独立运行,它需要运行在OAuth 2.0之上。OAuth仅专注于授权,而OIDC则添加了身份识别与验证方面的服务。
原文标题:Boost OAuth 2.0 and OpenID Connect Using Hooks,作者:Micah Silverman
【51CTO译稿,合作站点转载请注明原文译者和出处为51CTO.com】