2.2. JavaScript 适配器
Red Hat Single Sign-On 附带了一个客户端 JavaScript 库,可用于保护 HTML5/JavaScript 应用程序。JavaScript 适配器对 Cordova 应用程序进行了内置支持。
最好使用 NPM 或 Yarn 等软件包管理器在应用程序中包括 JavaScript 适配器。keycloak-js 软件包位于以下位置:
另外,还可直接从位于 /auth/js/keycloak.js 的 Red Hat Single Sign-On 服务器检索库,也可以作为 ZIP 存档分发。
需要注意的是使用客户端应用程序,客户端必须是公共客户端,因为无法安全地将客户端凭据存储在客户端应用中。这需要确保您为客户端配置的重定向 URI 正确且尽量具体。
要使用 JavaScript 适配器,您必须首先在 Red Hat Single Sign-On Admin Console 中为您的应用程序创建客户端。确保为 Access Type 选择了 public。您可以通过切换 OFF 客户端身份验证切换来实现此功能。
您还需要配置 有效的重定向 URI 和 Web Origins。具体来说,因为无法执行此操作,可能会导致安全漏洞。
创建客户端后,点右上角的 Action 选项卡,然后选择 Download adapter config。为 Format 选项 选择 Keycloak OIDC JSON,然后点 Download。下载的 keycloak.json 文件应当托管在您的 web 服务器上,其位置与您的 HTML 页面相同。
另外,您可以跳过配置文件并手动配置适配器。
以下示例演示了如何初始化 JavaScript 适配器:
如果 keycloak.json 文件位于您指定的不同位置:
const keycloak = new Keycloak('http://localhost:8080/myapp/keycloak.json');
const keycloak = new Keycloak('http://localhost:8080/myapp/keycloak.json');
或者,您可以使用所需配置在 JavaScript 对象中传递:
const keycloak = new Keycloak({
url: 'http://keycloak-server$/auth',
realm: 'myrealm',
clientId: 'myapp'
});
const keycloak = new Keycloak({
url: 'http://keycloak-server$/auth',
realm: 'myrealm',
clientId: 'myapp'
});
默认情况下,为了验证您需要调用 登录功能。但是,有两个选项可供适配器自动进行身份验证。您可以将 login-required 或 check-sso 传递给 init 功能。如果用户登录到 Red Hat Single Sign-On,或显示登录页面时,login-required 将验证客户端。只有用户尚未登录时,检查 关联才会验证客户端。如果该浏览器没有登录,则将重新指向应用并保持未经身份验证的。
您可以配置一个静默的 check-sso 选项。启用此功能后,您的浏览器不会完全重定向到 Red Hat Single Sign-On 服务器,再重新指向应用程序,但此操作将在隐藏的 iframe 中执行,因此只有当应用程序初始化并再次从红帽单点登录重新指向您的应用程序后,您的应用程序资源才需要被浏览器被加载和解析。在 SPA(Single Page Applications)时,这特别有用。
要启用il ent check-sso,您必须在 init 方法中提供 silentCheckSsoRedirectUri 属性。此 URI 需要是应用中的有效端点(当然,在 Red Hat Single Sign-On Admin Console 中,作为客户端的有效重定向):
keycloak.init({
onLoad: 'check-sso',
silentCheckSsoRedirectUri: window.location.origin + '/silent-check-sso.html'
})
keycloak.init({
onLoad: 'check-sso',
silentCheckSsoRedirectUri: window.location.origin + '/silent-check-sso.html'
})
在成功检查身份验证状态并从 Red Hat Single Sign-On 服务器检索令牌后,位于 ilent check-sso redirect uri 的页面会加载到 iframe 中。它没有其他任务,而不是将接收的令牌发送到主应用程序,应该只如下所示:
请注意,此页面的指定位置必须由应用程序本身提供,不是 JavaScript 适配器的一部分。
在某些现代浏览器中,静默的 check-sso 会有一些限制。请参阅带有跟踪保护部分的现代浏览器。
要在 Load to login-required 中将 login-required 设置为 login-required 并传递给 init 方法:
keycloak.init({
onLoad: 'login-required'
})
keycloak.init({
onLoad: 'login-required'
})
在用户通过身份验证后,通过在 Authorization 标头中包含 bearer 令牌,向红帽单点登录保护的 RESTful 服务发出请求。例如:
要记住的一点是,访问令牌默认具有简短的到期时间,因此您可能需要在发送请求前刷新访问令牌。您可以通过 updateToken 方法进行此操作。updateToken 方法会返回保证,只有在令牌成功刷新并向用户显示错误时,才会轻松地调用该服务。例如:
keycloak.updateToken(30).then(function() {
loadData();
}).catch(function() {
alert('Failed to refresh token');
});
keycloak.updateToken(30).then(function() {
loadData();
}).catch(function() {
alert('Failed to refresh token');
});
2.2.1. 会话状态 iframe 复制链接链接已复制到粘贴板!
默认情况下,JavaScript 适配器会创建一个隐藏 iframe,用于检测是否发生了 Single-Sign Out。这不需要任何网络流量,而是通过查看特殊状态 cookie 来检索的状态。通过在传递到 init 方法的选项中设置 checkLoginIframe: false 来禁用这个功能。
您不应该依赖于直接查看这个 cookie。其格式可能会改变,它也与 Red Hat Single Sign-On 服务器的 URL 关联,而不是您的应用程序。
在某些现代浏览器中,会话状态 iframe 功能有限。请参阅 带有跟踪保护部分的现代浏览器。
2.2.2. 隐式和混合流程 复制链接链接已复制到粘贴板!
默认情况下,JavaScript 适配器使用授权代码流。
通过这个流程,Red Hat Single Sign-On 服务器会向应用返回授权代码,而不是身份验证令牌。在浏览器重新定向到应用程序后,JavaScript 适配器会交换访问令牌 的代码 和刷新令牌。
Red Hat Single Sign-On 还支持 Implicit 流,在使用红帽单点登录验证成功后立即发送访问令牌。这可能比标准流性能更好,因为没有额外的请求交换令牌代码,但它在访问令牌过期时会产生影响。
但是,在 URL 片段中发送访问令牌可以是安全漏洞。例如,令牌可以通过 Web 服务器日志和浏览器历史记录泄露。
要启用隐式流,您需要在 Red Hat Single Sign-On Admin Console 中为客户端启用 Implicit Flow Enabled 标志。您还需要传递带有值 隐式 到 init 方法的参数 流 :
keycloak.init({
flow: 'implicit'
})
keycloak.init({
flow: 'implicit'
})
需要注意的一点是,只会提供访问令牌,且没有刷新令牌。这意味着,当访问令牌过期后,应用程序必须再次重定向到 Red Hat Single Sign-On,以获取新的访问令牌。
Red Hat Single Sign-On 还支持 混合 流程。
这要求客户端同时在管理控制台中启用 Standard Flow 和 Implicit Flow Enabled 标记。然后,Red Hat Single Sign-On 服务器会将代码和令牌发送到您的应用。访问令牌可以立即使用,而代码可以被交换用于访问和刷新令牌。与隐式流类似,混合流适合性能,因为访问令牌可以立即可用。但是,令牌仍然在 URL 中发送,前面提到的安全漏洞可能仍然适用。
混合流程的一个优点是,刷新令牌可供应用程序使用。
对于混合流程,您需要将参数 流 与值 hybrid 传递给 init 方法:
keycloak.init({
flow: 'hybrid'
})
keycloak.init({
flow: 'hybrid'
})
2.2.3. 带有 Cordova 的混合应用程序 复制链接链接已复制到粘贴板!
Keycloak 支持通过 Apache Cordova 开发的混合移动应用程序。JavaScript 适配器具有两种模式:cordova 和 cordova-native。
默认为 cordova,如果还没有配置适配器类型且存在 window.cordova,则适配器会自动选择。登录时,它会打开一个 InApp Browser,允许用户与红帽单点登录互动,然后再通过重定向到 http://localhost 来返回到应用程序。因此,您必须在管理控制台的客户端配置部分中将这个 URL 列列为有效的 redirect-uri。
虽然此模式易于设置,但它也有一些缺点:
- InApp-Browser 是嵌入在应用程序中且不是电话的默认浏览器的浏览器。因此,它将有不同的设置,存储的凭据将不可用。
- InApp-Browser 可能也较慢,特别是渲染更复杂的它们时。
- 在使用此模式前需要考虑安全性问题,例如,应用程序可以访问用户凭证,因为它可以完全控制浏览器渲染登录页面,因此不允许其在应用中使用它。
使用此示例应用程序帮助您入门 :https://github.com/keycloak/keycloak/tree/master/examples/cordova
另一种模式 cordova-native 采用不同的方法。它使用系统的浏览器打开登录页面。在用户通过身份验证后,浏览器会使用特殊的 URL 重新指向应用程序。在那里,Red Hat Single Sign-On 适配器可以通过从 URL 读取代码或令牌来完成登录。
您可以通过将适配器类型 cordova-native 传递给 init 方法来激活原生模式:
keycloak.init({
adapter: 'cordova-native'
})
keycloak.init({
adapter: 'cordova-native'
})
这个适配器需要两个附加插件:
- Cordova-plugin-browsertab :允许应用程序在系统浏览器中打开 Webpages
- Cordova-plugin-deeplinks :允许浏览器通过特殊 URL 将重新重定向到您的应用程序
每个平台上链接到应用程序的技术细节各有不同,且需要特殊设置。如需更多详情,请参阅 deeplinks 插件文档中的 Android 和 iOS 部分。
用于打开应用程序的不同链接:自定义方案(如 myapp://login 或 android-app://com.example.myapp/https/example.com/login)和 Universal Links(iOS))/ Deep Links(Android)。虽然前者易于设置并更可靠工作,但之后会提供额外的安全性,因为它们是唯一的,并且只有域的所有者可以注册它们。custom-URLs 在 iOS 中已弃用。我们建议您使用通用链接和回退站点,并在其中使用 custom-url 链接来获得最佳的可靠性。
另外,我们推荐以下步骤提高与 Keycloak 适配器的兼容性:
-
iOS 上的 Universal Links 似乎可以在将
response-mode设置为query时更可靠地工作 -
要防止 Android 在重定向时打开应用程序的新实例,请将以下代码片段添加到
config.xml中:
<preference name="AndroidLaunchMode" value="singleTask" />
<preference name="AndroidLaunchMode" value="singleTask" />
一个示例应用程序演示了如何使用 native-mode: https://github.com/keycloak/keycloak/tree/master/examples/cordova-native
2.2.4. 自定义适配器 复制链接链接已复制到粘贴板!
有时需要运行默认不支持的 JavaScript 客户端(如 Capacitor)。要在这些未知环境中使用 JavasScript 客户端,可以传递自定义适配器。例如,第三方库可能会提供这样的适配器,以便可以在没有问题的情况下运行 JavaScript 客户端:
这个特定软件包不存在,但它会提供一个很好的示例来把这个适配器传递给客户端。
也可以让自己的适配器实现,因此您必须实现 KeycloakAdapter 接口中描述的方法。例如,以下 TypeScript 代码确保正确实施所有方法:
通过省略类型信息来确保正确实施接口将完全保留给您,那么在一定程度上,您也可以在不进行 TypeScript 的情况下执行此操作。
2.2.5. 早期浏览器 复制链接链接已复制到粘贴板!
JavaScript 适配器依赖于 Base64(window.btoa 和 window.atob)、HTML5 History API 以及可选的 Promise API。如果您需要支持没有这些可用的浏览器(例如,IE9),则需要添加填充器。
polyfill 库示例:
- Base64 - https://github.com/davidchambers/Base64.js
- HTML5 History - https://github.com/devote/HTML5-History-API
- Promise - https://github.com/stefanpenner/es6-promise
2.2.6. 带有跟踪保护的现代浏览器 复制链接链接已复制到粘贴板!
应用了各种浏览器的最新版本中的 Cookie 策略,以防止由第三方(如 Chrome 中的 SameSite)跟踪用户,或者完全阻止了第三方 Cookie。预计这些策略会随着时间的推移而变得更严格的限制,并由其他浏览器采用,最终导致浏览器不支持并阻止第三方上下文中的 Cookie。受此问题影响的适配器功能可能会在以后被弃用。
JavaScript 适配器依赖于 Session Status iframe、静默 check-sso 以及部分常规(非静默)check-sso。这些功能有限,或者完全禁用,具体取决于浏览器对 Cookie 的限制程度。适配器会尝试检测此设置并相应地做出反应。
2.2.6.1. 带有 "SameSite=Lax by Default" Policy 的浏览器 复制链接链接已复制到粘贴板!
如果在 Red Hat Single Sign-On side 以及应用程序端配置 SSL / TLS 连接,则所有功能均被支持。受影响(例如,从版本 84 开始的 Chrome)。
2.2.6.2. 带有 Blocked 第三方 Cookies 的浏览器 复制链接链接已复制到粘贴板!
不支持会话状态 iframe,如果 JS 适配器检测到这样的浏览器行为,则会自动禁用。这意味着适配器无法将会话 cookie 用于单点登录检测,且必须完全依赖令牌。这意味着,当用户在另一个窗口中注销时,使用 JavaScript 适配器的应用程序不会注销,直到它尝试刷新 Access Token。因此,建议您将 Access Token Lifespan 设置为相对较短的时间,因此会检测到注销,而不是早于以后的版本。请查看 会话和令牌超时。
不支持静默 check-sso ,会默认回退到常规(非静默)check-sso。通过在传递到 init 方法的选项中设置 silentCheckSsoFallback: false 来更改这种行为。在这种情况下,如果检测到限制性浏览器行为,check-sso 会被完全禁用。
定期 的检查 也会受到影响。由于 Session Status iframe 不被支持,因此当适配器被初始化以检查用户的登录状态时,必须进行额外的重定向到红帽单点登录。当 iframe 用于识别用户是否登录时,这与标准行为不同,且仅在登出时执行重定向。
受影响的浏览器是 Safari 从版本 13.1 开始。
2.2.7. JavaScript Adapter 参考 复制链接链接已复制到粘贴板!
2.2.7.1. Constructor 复制链接链接已复制到粘贴板!
new Keycloak();
new Keycloak('http://localhost/keycloak.json');
new Keycloak({ url: 'http://localhost/auth', realm: 'myrealm', clientId: 'myApp' });
new Keycloak();
new Keycloak('http://localhost/keycloak.json');
new Keycloak({ url: 'http://localhost/auth', realm: 'myrealm', clientId: 'myApp' });
2.2.7.2. Properties 复制链接链接已复制到粘贴板!
- 已验证
-
如果用户通过身份验证,则为
true,否则为false。 - token
-
base64 编码的令牌,可在请求到服务的
Authorization标头中发送。 - tokenParsed
- 解析的令牌作为一个 JavaScript 对象。
- subject
- 用户 ID。
- idToken
- base64 编码的 ID 令牌。
- idTokenParsed
- 解析的 id 令牌作为 JavaScript 对象。
- realmAccess
- 与令牌关联的 realm 角色。
- resourceAccess
- 与令牌关联的资源角色。
- refreshToken
- base64 编码的刷新令牌,可用于检索新令牌。
- refreshTokenParsed
- 被解析的刷新令牌为 JavaScript 对象。
- timeSkew
- 浏览器时间和红帽单点登录服务器之间的时间差差以秒为单位。这个值只是一个估算值,但在确定令牌是否过期时准确。
- responseMode
- 以 init 传递的响应模式(默认值为片段)。
- 流
- 在 init 中传递的流程。
- adapter
允许您覆盖重定向和其他浏览器相关功能的方式由该库处理。可用选项:
- "默认" - 库使用浏览器 api 进行重定向(这是默认设置)
- "Cordova" - 库将尝试使用 InAppBrowser cordova 插件加载 keycloak 登录/registration 页面(当库在 cordova 生态系统中工作时会自动使用)
- "Cordova-native" - 库尝试使用浏览器使用 BrowserTabs cordova 插件打开登录和注册页面。这需要额外的设置来重定向到应用程序(请参阅 第 2.2.3 节 “带有 Cordova 的混合应用程序”)。
- "custom" - 允许您实现自定义适配器(仅适用于高级用例)
- responseType
- 使用登录请求发送到 Red Hat Single Sign-On 的响应类型。这根据初始化过程中所用的流值来确定,但可通过设置此值来覆盖。
2.2.7.3. Methods 复制链接链接已复制到粘贴板!
init (options)
名为 初始化适配器。
选项是一个对象,其中:
-
useNonce - 添加加密非密码以验证身份验证响应是否与请求匹配(默认为
true)。 -
onLoad - 指定要对负载执行的操作。支持的值有
login-required或check-sso。 - silentCheckSsoRedirectUri - 在Load 上将 redirect uri for silent authentication check 设置为 'check-sso'。
-
silentCheckSsoFallback - 当浏览器不支持 静默
check-sso时(默认为true),启用回到普通的check-sso。 - token - 为令牌设置初始值。
- refreshToken - 为刷新令牌设置初始值。
- idToken - 为 id 令牌设置初始值(仅与令牌或刷新Token 一起)。
-
Scope - 将默认 scope 参数设置为 Red Hat Single Sign-On 登录端点。使用以空格分隔的范围列表。它们通常引用 特定客户端中定义的客户端范围。请注意,scope
openid始终会添加到适配器的范围列表中。例如,如果您输入范围选项地址电话,则到 Red Hat Single Sign-On 的请求将包含 scope 参数scope=openid 地址电话。请注意,如果login ()选项明确指定范围,则这里指定的默认范围会被覆盖。 - timeSkew - 为本地时间和 Red Hat Single Sign-On 服务器(仅与令牌或刷新Token)之间设置一个初始值。
-
checkLoginIframe - Set to enable/disable monitoring login status(默认为
true)。 - checkLoginIframeInterval - 设置用于检查登录状态的时间间隔(默认为 5 秒)。
-
responseMode - 在登录请求时设置 OpenID Connect 响应模式发送到 Red Hat Single Sign-On 服务器。有效值为
query或fragment。默认值为片段,这意味着在成功验证后,Red Hat Single Sign-On 会重定向到 JavaScript 应用,并在 URL 片段中添加 OpenID Connect 参数。这通常更安全,建议使用它而不是query。 -
流 - 设置 OpenID Connect 流。有效值为
标准、隐式或混合。 -
enableLogging - 启用从 Keycloak 到控制台的日志记录信息(默认为
false)。 pkceMethod - 要使用的概念验证交换方法(PKCE)。配置此值可启用 PKCE 机制。可用选项:
- "S256" - 基于 SHA256 的 PKCE 方法
- messageReceiveTimeout - 为等待 Keycloak 服务器的消息响应设置超时(毫秒)。这用于,例如,在第三方 Cookie 检查期间等待消息。默认值为 10000。
返回初始化完成后可以解决的保证。
login(options)
重定向至登录表单.
选项是一个可选对象,其中:
- redirecturi - 指定在登录后要重定向到的 uri。
-
提示 - 这个参数允许在 Red Hat Single Sign-On 服务器端稍自定义登录流。例如,使用值 登录时,强制显示
登录屏幕。如需提示参数的详细信息和所有可能值,请参阅 参数转发 部分。 -
maxAge - 仅在用户已通过身份验证时才使用。指定用户验证发生以来的最大时间。如果用户已通过身份验证的时间超过
maxAge,则 SSO 将被忽略,而且需要重新验证。 - loginHint - 用来预先填充登录表单上的用户名/电子邮件字段。
-
Scope - 覆盖
init中配置的范围,这个特定登录的不同值。 - idpHint - 用来告诉 Red Hat Single Sign-On 跳过显示登录页面并自动重定向到指定的身份提供程序。身份提供程序文档中的更多信息。
-
acr- 包含关于授权信息,该声明将在声明参数内部发送到 Red Hat Single Sign-On 服务器。典型的用法用于步骤验证。使用{ values: ["silver", "gold"], essential: true }的示例。如需了解更多详细信息,请参阅 OpenID Connect 规格和增强身份验证文档。 -
action - 如果
注册值,则将用户重定向到注册页面,如果值为UPDATE_PASSWORD,则用户将重定向到重置密码页面(如果未验证,则首先向登录页面发送用户,并在身份验证后重定向到登录页面),否则重定向到登录页面。 - locale - 设置"ui_locales"查询 param,与 OIDC 1.0 规范的第 3.1.2.1 节 保持一致。
-
cordovaOptions - 指定传递给 ordova in-app-browser(如果适用)的参数。选择
hidden和location不受这些参数的影响。所有可用选项均在 https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-inappbrowser/ 中定义。使用示例:{ zoom: "no", hardwareback: "yes" };
createLoginUrl(options)
返回 URL to login 表单。
选项是一个可选对象,也支持与功能 登录 相同的选项。
logout (options)
重定向至注销.
选项是一个对象,其中:
- redirecturi - 指定在注销后要重定向到的 uri。
createLogoutUrl(options)
返回 URL 以注销用户。
选项是一个对象,其中:
- redirecturi - 指定在注销后要重定向到的 uri。
register (options)
重定向至注册表单。使用选项 action 进行登录的快捷方式 = 'register'
的选项与登录方法相同,但 'action' 设置为 'register'
createRegisterUrl(options)
返回 url to registration 页面。带有选项 action 的 createLoginUrl 的快捷方式 = 'register'
选项与 createLoginUrl 方法相同,但 'action' 设置为 'register'
accountManagement()
重定向到帐户管理控制台。
createAccountUrl(options)
返回帐户管理控制台的 URL。
选项是一个对象,其中:
- redirecturi - 指定在重定向到应用程序时要重定向到的 uri。
hasRealmRole(role)
如果令牌具有给定 realm 角色,则返回 true。
hasResourceRole (role, resource)
如果令牌具有资源的给定角色,则返回 true(如果不使用指定 clientId,资源是可选的)。
loadUserProfile()
加载用户配置文件。
返回可通过配置集解决的保证。
例如:
isTokenExpired(minValidity)
如果令牌在过期前的 minValidity 少于 minValidity 秒,则返回为 true(如果未指定 0 则是可选的)。
updateToken(minValidity)
如果令牌在 minValidity 秒内过期(如果未使用 5,则为minValidity 是可选的),则令牌会被刷新。如果 -1 作为 minValidity 传递,则令牌将被强制刷新。如果启用了会话状态 iframe,还会检查会话状态。
返回通过布尔值解析的指示是否刷新令牌的布尔值。
例如:
clearToken()
清除身份验证状态,包括令牌。如果应用程序检测到会话已过期,例如更新令牌失败,这很有用。
调用此操作会导致被调用AuthLogout 回调监听程序。
2.2.7.4. 回调事件 复制链接链接已复制到粘贴板!
适配器支持为特定事件设置回调监听程序。请记住,必须在调用 init 功能前设置它们。
例如:
keycloak.onAuthSuccess = function() { alert('authenticated'); }
keycloak.onAuthSuccess = function() { alert('authenticated'); }
可用的事件有:
- onReady (authenticated) - 在适配器初始化时调用。
- onAuthSuccess - 当用户成功验证时调用。
- onAuthError - 如果身份验证过程中出现错误,则调用。
- onAuthRefreshSuccess - 刷新令牌时调用。
- onAuthRefreshError - 如果尝试刷新令牌时出现错误,则调用。
- onAuthLogout - 只有启用了会话状态 iframe 或 Cordova 模式时,才会调用调用(只有在启用了会话状态 iframe 时)。
- onTokenExpired - 当访问令牌过期时调用。如果有可用的刷新令牌,可以使用 updateToken 刷新令牌,或者在没有(也就是说,带有隐式流)的情况下,您可以重定向到登录屏幕以获取新的访问令牌。