SSO 和 SAML - 多个服务提供商
SSO and SAML - Multiple Services Providers
我有两个 Spring 使用 Spring 安全 SAML 扩展保护的启动应用程序。这两个应用程序已经 运行。第一个 (web-ui-app) 是第二个 (services-app) 的用户界面,一个 REST API.
成功访问 web-ui-app 后,通过身份提供者正确验证,我尝试访问一些服务-app 的方法。
但是,我没有收到来自 services-app 的正确响应 JSON 响应,而是收到如下内容:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<body onload="document.forms[0].submit()">
<noscript>
<p>
<strong>Note:</strong> Since your browser does not support JavaScript, you must press the Continue button once to proceed.
</p>
</noscript>
<form action="https://ServiceProvider.com/SAML/SLO/Browser" method="post">
<div>
<input type="hidden" name="RelayState" value="0043bfc1bc45110dae17004005b13a2b"/>
<input type="hidden" name="SAMLRequest" value="PHNhbWxwOkxvZ291dFJlcXVlc3QgeG1sbnM6c2FtbHA9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpwcm90b2NvbCIgeG1sbnM9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphc3NlcnRpb24iDQogICAgSUQ9ImQyYjdjMzg4Y2VjMzZmYTdjMzljMjhmZDI5ODY0NGE4IiBJc3N1ZUluc3RhbnQ9IjIwMDQtMDEtMjFUMTk6MDA6NDlaIiBWZXJzaW9uPSIyLjAiPg0KICAgIDxJc3N1ZXI+aHR0cHM6Ly9JZGVudGl0eVByb3ZpZGVyLmNvbS9TQU1MPC9Jc3N1ZXI+DQogICAgPE5hbWVJRCBGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpuYW1laWQtZm9ybWF0OnBlcnNpc3RlbnQiPjAwNWEwNmUwLWFkODItMTEwZC1hNTU2LTAwNDAwNWIxM2EyYjwvTmFtZUlEPg0KICAgIDxzYW1scDpTZXNzaW9uSW5kZXg+MTwvc2FtbHA6U2Vzc2lvbkluZGV4Pg0KPC9zYW1scDpMb2dvdXRSZXF1ZXN0Pg=="/>
</div>
<noscript>
<div>
<input type="submit" value="Continue"/>
</div>
</noscript>
</form>
</body>
</html>
这是 SSO 对话。既然我已经通过 web-ui-app 登录,难道它不应该是 services-app 和服务提供商之间的透明密钥交换吗?
我错过了什么?
SAML 可用于保护具有其余部分的单个应用程序 API,但是,具有不共享应用程序或会话上下文的单独前端和后端不起作用。例如,如果您有一个打包了前端的单个应用程序并将其配置为单个服务提供者,则该会话将对后端 API 请求有效。
也就是说,如果您将前端配置为服务提供者,您可以使用基于无状态令牌的安全性来实现 REST API,正如您所提到的。这种架构是首选,因为它比会话更好。任何请求都应该能够转到 REST API 的任何实例并得到处理,因此您可以添加或删除 API 的实例以根据需要扩展应用程序。
JSON Web Tokens (JWT) 是一个不错的选择,因为它允许您在令牌内的自定义声明中存储一些有关用户的信息。如果其余 API 的所有实例都使用相同的共享密钥对令牌进行签名,则任何请求都可以转到任何实例,并且该实例将能够解码令牌并获取声明信息(例如用户 ID),而无需必须将其存储在内存缓存或数据库中。
我有两个 Spring 使用 Spring 安全 SAML 扩展保护的启动应用程序。这两个应用程序已经 运行。第一个 (web-ui-app) 是第二个 (services-app) 的用户界面,一个 REST API.
成功访问 web-ui-app 后,通过身份提供者正确验证,我尝试访问一些服务-app 的方法。
但是,我没有收到来自 services-app 的正确响应 JSON 响应,而是收到如下内容:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<body onload="document.forms[0].submit()">
<noscript>
<p>
<strong>Note:</strong> Since your browser does not support JavaScript, you must press the Continue button once to proceed.
</p>
</noscript>
<form action="https://ServiceProvider.com/SAML/SLO/Browser" method="post">
<div>
<input type="hidden" name="RelayState" value="0043bfc1bc45110dae17004005b13a2b"/>
<input type="hidden" name="SAMLRequest" value="PHNhbWxwOkxvZ291dFJlcXVlc3QgeG1sbnM6c2FtbHA9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpwcm90b2NvbCIgeG1sbnM9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphc3NlcnRpb24iDQogICAgSUQ9ImQyYjdjMzg4Y2VjMzZmYTdjMzljMjhmZDI5ODY0NGE4IiBJc3N1ZUluc3RhbnQ9IjIwMDQtMDEtMjFUMTk6MDA6NDlaIiBWZXJzaW9uPSIyLjAiPg0KICAgIDxJc3N1ZXI+aHR0cHM6Ly9JZGVudGl0eVByb3ZpZGVyLmNvbS9TQU1MPC9Jc3N1ZXI+DQogICAgPE5hbWVJRCBGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpuYW1laWQtZm9ybWF0OnBlcnNpc3RlbnQiPjAwNWEwNmUwLWFkODItMTEwZC1hNTU2LTAwNDAwNWIxM2EyYjwvTmFtZUlEPg0KICAgIDxzYW1scDpTZXNzaW9uSW5kZXg+MTwvc2FtbHA6U2Vzc2lvbkluZGV4Pg0KPC9zYW1scDpMb2dvdXRSZXF1ZXN0Pg=="/>
</div>
<noscript>
<div>
<input type="submit" value="Continue"/>
</div>
</noscript>
</form>
</body>
</html>
这是 SSO 对话。既然我已经通过 web-ui-app 登录,难道它不应该是 services-app 和服务提供商之间的透明密钥交换吗?
我错过了什么?
SAML 可用于保护具有其余部分的单个应用程序 API,但是,具有不共享应用程序或会话上下文的单独前端和后端不起作用。例如,如果您有一个打包了前端的单个应用程序并将其配置为单个服务提供者,则该会话将对后端 API 请求有效。
也就是说,如果您将前端配置为服务提供者,您可以使用基于无状态令牌的安全性来实现 REST API,正如您所提到的。这种架构是首选,因为它比会话更好。任何请求都应该能够转到 REST API 的任何实例并得到处理,因此您可以添加或删除 API 的实例以根据需要扩展应用程序。
JSON Web Tokens (JWT) 是一个不错的选择,因为它允许您在令牌内的自定义声明中存储一些有关用户的信息。如果其余 API 的所有实例都使用相同的共享密钥对令牌进行签名,则任何请求都可以转到任何实例,并且该实例将能够解码令牌并获取声明信息(例如用户 ID),而无需必须将其存储在内存缓存或数据库中。