2.4. 红帽构建的 Keycloak JavaScript 适配器
红帽构建的 Keycloak 附带一个名为 keycloak-js
的客户端 JavaScript 库,可用于保护 Web 应用程序。适配器还包括对 Cordova 应用程序的内置支持。
2.4.1. 安装
适配器以多种方式发布,但我们建议您从 NPM 安装 keycloak-js
软件包:
npm install keycloak-js
另外,该库可以直接从位于 /js/keycloak.js
的 Keycloak 服务器的红帽构建中检索,也可以作为 ZIP 存档分发。但是,我们考虑从 Keycloak 服务器直接包含适配器已被弃用,这个功能可能会在以后被删除。
2.4.2. 红帽构建的 Keycloak 服务器配置
要考虑使用客户端侧应用的一个重要事项是客户端必须是公共客户端,因为无法将客户端凭据存储在客户端侧应用中。考虑到这一点,请确保您为客户端配置的重定向 URI 正确且尽量具体。
要使用适配器,请在红帽构建的 Keycloak 管理控制台中为应用程序创建一个客户端。通过将客户端身份验证切换为 Off 在 Capability 配置页面中使客户端变为 Off。
您还需要配置 Valid Redirect URI
和 Web Origins
。尽可能具体,因为无法这样做,可能会导致安全漏洞。
2.4.3. 使用适配器
以下示例演示了如何初始化适配器。确保将传递给 Keycloak
构造器的选项替换为您配置的客户端。
import Keycloak from 'keycloak-js'; const keycloak = new Keycloak({ url: 'http://keycloak-server${kc_base_path}', realm: 'myrealm', clientId: 'myapp' }); try { const authenticated = await keycloak.init(); console.log(`User is ${authenticated ? 'authenticated' : 'not authenticated'}`); } catch (error) { console.error('Failed to initialize adapter:', error); }
要进行身份验证,您需要调用 登录
功能。有两个选项以使适配器自动验证。您可以将 login-required
或 check-sso
传递给 init ()
函数。
-
如果用户登录到红帽构建的 Keycloak,则
login-required
验证客户端,如果用户没有登录,则会显示登录页面。 -
check-sso
仅在用户已经登录时才验证客户端。如果用户没有登录,浏览器会被重定向到应用程序,并保持未经身份验证的。
您可以配置一个静默的 check-sso
选项。启用这个功能后,您的浏览器不会对红帽构建的 Keycloak 服务器执行完全重定向到您的应用程序,但此操作将在隐藏的 iframe 中执行。因此,您的应用程序资源只会由浏览器加载并解析一次,即在应用程序被初始化时,而不是在从红帽构建的 Keycloak 重新到应用程序后再次解析。对于 SPAs (Single Page Applications),此方法特别有用。
要启用 silent check-sso
,您可以在 init 方法中提供 silentCheckSsoRedirectUri
属性。确保此 URI 是应用程序中的有效端点;它必须配置为红帽构建的 Keycloak 管理控制台中的客户端的有效重定向:
keycloak.init({ onLoad: 'check-sso', silentCheckSsoRedirectUri: `${location.origin}/silent-check-sso.html` });
在成功检查身份验证状态并从红帽 Keycloak 服务器检索令牌后,silent check-sso redirect uri 会加载到 iframe 中。除了将接收的令牌发送到主应用程序外,它没有其他任务,应该只类似如下:
<!doctype html> <html> <body> <script> parent.postMessage(location.href, location.origin); </script> </body> </html>
请记住,此页面必须由您的应用程序在 silentCheckSsoRedirectUri
中的指定位置提供,且不是 适配器的一部分。
在某些现代浏览器中,静默的 check-sso
会有一些限制。请参阅带有跟踪保护部分的现代浏览器。
要在 Load to
login-required
上启用login-required
设置为 login-required,并传递给 init 方法:
keycloak.init({ onLoad: 'login-required' });
在经过身份验证后,应用程序可以通过在 Authorization
标头中包含 bearer 令牌来向红帽构建的 Keycloak 安全的 RESTful 服务发出请求。例如:
async function fetchUsers() { const response = await fetch('/api/users', { headers: { accept: 'application/json', authorization: `Bearer ${keycloak.token}` } }); return response.json(); }
请记住,访问令牌默认具有较短的过期时间,因此您可能需要在发送请求前刷新访问令牌。您可以通过调用 updateToken ()
方法来刷新此令牌。这个方法会返回 Promise,它可让您仅在成功刷新令牌时轻松调用该服务,并在用户未刷新时向用户显示一个错误。例如:
try { await keycloak.updateToken(30); } catch (error) { console.error('Failed to refresh token:', error); } const users = await fetchUsers();
访问和刷新令牌都存储在内存中,且不会保留在任何类型的存储中。因此,这些令牌永远不会被保留,以防止劫持攻击。
2.4.4. 会话状态 iframe
默认情况下,适配器会创建一个隐藏的 iframe,用于检测是否发生 Single-Sign Out。这个 iframe 不需要任何网络流量。相反,通过查看特殊的状态 cookie 来检索状态。通过在传递给 init ()
方法的选项中设置 checkLoginIframe: false
来禁用此功能。
您不应该直接查看这个 Cookie。其格式可能会改变,它还与红帽构建的 Keycloak 服务器的 URL 关联,而不是您的应用程序。
会话状态 iframe 功能在某些现代浏览器中受到限制。请参阅 带有跟踪保护部分的现代浏览器。
2.4.5. 隐式和混合流
默认情况下,适配器使用 Authorization Code 流。
在这个版本中,红帽构建的 Keycloak 服务器会将授权代码而不是身份验证令牌返回给应用程序。JavaScript 适配器在浏览器重定向到应用程序后交换访问令牌的代码和刷新令牌。
红帽构建的 Keycloak 还支持 Implicit 流,在通过红帽构建的 Keycloak 身份验证成功后立即发送访问令牌。此流的性能可能比标准流更强,因为不存在额外的请求来交换令牌的代码,但在访问令牌过期时有影响。
但是,在 URL 片段中发送访问令牌可能是一个安全漏洞。例如,令牌可能会通过 Web 服务器日志或浏览器历史记录泄漏。
要启用隐式流,您可以在红帽构建的 Keycloak 管理控制台中为客户端启用 Implicit Flow Enabled 标志。您还将参数 流
传递值为 implicit
到 init
方法:
keycloak.init({ flow: 'implicit' })
请注意,只提供访问令牌,且没有刷新令牌。这意味着,一旦访问令牌已过期,应用程序必须重新重定向到红帽构建的 Keycloak,以获取新的访问令牌。
红帽构建的 Keycloak 还支持 混合 流。
此流要求客户端在管理控制台中 同时启用 了标准流和 Implicit 流。然后,红帽构建的 Keycloak 服务器会将代码和令牌发送到您的应用程序。访问令牌可以立即使用,同时可以交换代码来访问和刷新令牌。与隐式流类似,混合流对性能很好,因为访问令牌会立即可用。但是,令牌仍然在 URL 中发送,前面提到的安全漏洞可能仍然适用。
混合流中的一个优点是刷新令牌可供应用程序使用。
对于混合流,您需要将带有值 hybrid
参数 流
传递给 init
方法:
keycloak.init({ flow: 'hybrid' });
2.4.6. Cordova 的混合应用程序
红帽构建的 Keycloak 支持使用 Apache Cordova 开发的混合移动应用程序。适配器具有两种模式: cordova
和 cordova-native
:
默认为 cordova
,如果没有显式配置适配器类型,且存在 window.cordova
,则适配器会自动选择它。登录时,它会打开一个 InApp Browser,允许用户与红帽构建的 Keycloak 交互,随后通过重定向到 http://localhost
来返回到应用程序。由于此行为,您可以在管理控制台的客户端配置部分中将此 URL 列为有效的 redirect-uri。
虽然此模式易于设置,但也有一些缺点:
- InApp-Browser 是嵌入在应用程序中的浏览器,不是电话的默认浏览器。因此,它具有不同的设置,并且存储的凭据将不可用。
- InApp-Browser 可能也很慢,特别是在渲染更复杂的主题时。
- 在使用此模式之前,需要注意一些安全性问题,例如,应用程序有可能获得用户凭证的访问权限,因为它对浏览器的渲染登录页面具有完全控制,因此不允许它在不信任的应用中使用。
另一种模式是'cordova-native',它采用不同的方法。它使用系统的浏览器打开登录页面。用户通过身份验证后,浏览器将使用特殊 URL 重新重定向到应用。在这里,红帽构建的 Keycloak 适配器可以通过从 URL 读取代码或令牌来完成登录。
您可以通过将 adapter 类型 cordova-native
传递给 init ()
方法来激活原生模式:
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 链接的回退站点结合使用。
另外,我们建议以下步骤提高与适配器的兼容性:
-
iOS 上的通用链接看似更可靠工作,并将
response-mode
设置为query
-
要防止 Android 在重定向时打开应用程序的新实例,请将以下代码片段添加到
config.xml
中:
<preference name="AndroidLaunchMode" value="singleTask" />
2.4.7. 自定义适配器
在某些情况下,您可能需要在不受默认支持的环境中运行适配器,如 Capacitor。要在这些环境中使用 JavasScript 客户端,您可以传递自定义适配器。例如,第三方库可以提供这样的适配器,以便可以可靠地运行适配器:
import Keycloak from 'keycloak-js'; import KeycloakCapacitorAdapter from 'keycloak-capacitor-adapter'; const keycloak = new Keycloak(); keycloak.init({ adapter: KeycloakCapacitorAdapter, });
这个特定软件包不存在,但它是一个很好的例子,它是如何传递给客户端的适配器。
也可以自行创建适配器,您必须实施 KeycloakAdapter
接口中描述的方法。例如,以下 TypeScript 代码确保所有方法都被正确实现:
import Keycloak, { KeycloakAdapter } from 'keycloak-js'; // Implement the 'KeycloakAdapter' interface so that all required methods are guaranteed to be present. const MyCustomAdapter: KeycloakAdapter = { login(options) { // Write your own implementation here. } // The other methods go here... }; const keycloak = new Keycloak(); keycloak.init({ adapter: MyCustomAdapter, });
通过省略类型信息,您也可以在没有 TypeScript 的情况下执行此操作,但确保正确实现接口将完全保留给您。
2.4.8. 带有跟踪保护的现代浏览器
在最新版本的某些浏览器中,会应用各种 Cookie 策略,以防止由第三方跟踪用户,如 Chrome 中的 SameSite 或完全阻止第三方 Cookie。这些策略可能会变得更严格并被其他浏览器随时间采用。最终,第三方上下文中的 Cookie 可能会完全不受支持,并由浏览器阻止。因此,受影响的适配器功能可能会最终被弃用。
适配器依赖于 Session Status iframe、静默 check-sso
以及部分常规(非静默) check-sso
。这些功能有有限的功能,或者根据浏览器对 Cookie 的限制而完全禁用。适配器会尝试检测此设置并相应地响应。
2.4.8.1. 带有 "SameSite=Lax by Default" 策略的浏览器
如果在红帽构建的 Keycloak 端以及应用程序端配置了 SSL / TLS 连接,则所有功能都被支持。例如:从版本 84 开始,Chrome 会受到影响。
2.4.8.2. 带有块第三方 Cookie 的浏览器
不支持会话状态 iframe,如果适配器检测到这样的浏览器行为,则会自动禁用。这意味着适配器无法将会话 Cookie 用于 Single Sign-Out 检测,且必须完全依赖令牌。因此,当用户在另一个窗口中登录时,使用适配器的应用程序不会登出,直到应用程序尝试刷新访问令牌为止。因此,请考虑将 Access Token Lifespan 设置为相对较短的时间,以便尽快检测到注销。如需了解更多详细信息,请参阅 会话和令牌超时。
不支持静默 check-sso
,会默认回退到常规(非静默)check-sso
。通过在传递给 init
方法的选项中设置 silentCheckSsoFallback: false
来更改此行为。在这种情况下,如果检测到限制性浏览器行为,check-sso
会被完全禁用。
常规 check-sso
也会受到影响。由于 Session Status iframe 不受支持,因此在适配器初始化以检查用户的登录状态时,必须进行到红帽构建的 Keycloak 的额外重定向。当 iframe 用于告知用户是否登录时,此检查与标准行为不同,并且仅在用户注销时才执行重定向。
受影响的浏览器是从版本 13.1 开始的 Safari 示例。
2.4.9. API 参考
2.4.9.1. Constructor
new Keycloak(); new Keycloak('http://localhost/keycloak.json'); new Keycloak({ url: 'http://localhost', realm: 'myrealm', clientId: 'myApp' });
2.4.9.2. Properties
- 已验证
-
如果用户通过身份验证,则为
true
,否则为false
。 - token
-
可以在请求中的
Authorization
标头发送到服务的 base64 编码令牌。 - tokenParsed
- 解析的令牌作为一个 JavaScript 对象。
- subject
- 用户 ID。
- idToken
- base64 编码的 ID 令牌。
- idTokenParsed
- 解析的 id 令牌作为 JavaScript 对象。
- realmAccess
- 与令牌关联的 realm 角色。
- resourceAccess
- 与令牌关联的资源角色。
- refreshToken
- base64 编码的刷新令牌,可用于检索新令牌。
- refreshTokenParsed
- 解析的刷新令牌作为 JavaScript 对象。
- timeSkew
- 浏览器时间和红帽构建的 Keycloak 服务器之间的预计时间差异(以秒为单位)。这个值只是一个估算,但在确定令牌是否过期时足够准确。
- responseMode
- 在 init 中传递的响应模式(默认值为 片段)。
- 流
- 在 init 中传递的流程。
- adapter
允许您覆盖重定向和其他浏览器相关功能的方式由该库处理。可用选项:
- "default" - 库使用浏览器 api 进行重定向(这是默认设置)
- "Cordova" - 库将尝试使用 InAppBrowser cordova 插件来加载 keycloak 登录/注册页面(当库在 cordova 生态系统中工作)
- "Cordova-native" - 库尝试使用浏览器Tabs cordova 插件使用电话的系统浏览器打开登录和注册页面。这需要额外的设置才能重新重定向到应用程序(请参阅 第 2.4.6 节 “Cordova 的混合应用程序”)。
- "custom" - 允许您实施自定义适配器(仅适用于高级用例)
- responseType
- 发送到带有登录请求的红帽构建的 Keycloak 的响应类型。这根据初始化过程中使用的流值决定,但可通过设置这个值来覆盖。
2.4.9.3. Methods
init (options)
调用以初始化适配器。
选项是一个对象,其中:
-
useNonce - 添加加密非ce 以验证身份验证响应是否与请求匹配(默认为
true
)。 -
onLoad - 指定加载时要执行的操作。支持的值是
login-required
或check-sso
。 - silentCheckSsoRedirectUri - 如果 onLoad 设为 'check-sso',则设置重定向 uri for silent authentication check。
-
silentCheckSsoFallback - 当浏览器不支持 静默
check-sso
时(默认为true
),启用回到普通的check-sso
。 - token - 为令牌设置初始值。
- refreshToken - 为刷新令牌设置初始值。
- idToken - 为 id 令牌设置一个初始值(仅适用于 token 或 refreshToken)。
-
Scope - 将默认范围参数设置为红帽构建的 Keycloak 登录端点。使用以空格分隔的范围列表。它们通常引用 在特定客户端上定义的客户端范围。请注意,范围
openid
将始终添加到适配器的范围列表中。例如,如果您输入范围选项地址电话
,则对红帽构建的 Keycloak 的请求将包含scope=openid 地址电话
。请注意,如果login ()
选项明确指定范围,则此处指定的默认范围会被覆盖。 - timeSkew - 以秒为单位为 skew 和 Red Hat build of Keycloak 服务器设置初始值(仅与 token 或 refreshToken 一起)。
-
checkLoginIframe - 设置为启用/禁用监控登录状态(默认为
true
)。 - checkLoginIframeInterval - 设置检查登录状态的时间间隔(默认为 5 秒)。
-
responseMode - 在登录请求时设置 OpenID Connect 响应模式向红帽构建的 Keycloak 服务器发送。有效值为
query
或fragment
。默认值为fragment
,这意味着,在成功身份验证后,红帽构建 Keycloak 重定向到 JavaScript 应用程序,并在 URL 片段中添加 OpenID Connect 参数。这通常更安全,建议使用它而不是query
。 -
flow - 设置 OpenID Connect 流。有效值为
标准
、隐式
或混合
。 -
enableLogging - 启用从 Keycloak 到控制台的日志记录信息(默认为
false
)。 pkceMethod - 要使用的概念验证代码交换(PKCE)的方法。配置这个值可启用 PKCE 机制。可用选项:
- "S256" - 基于 SHA256 的 PKCE 方法(默认)
- false - 禁用 PKCE。
-
acrValues - 生成
acr_values
参数,该参数引用身份验证上下文类引用,并允许客户端声明所需的保证级别要求,如验证机制。请参阅 OpenID Connect MODRNA Authentication Profile 1.0 中的第 4 节 cr_values 请求值和保证级别。 - messageReceiveTimeout - 以毫秒为单位设置一个超时,用于等待 Keycloak 服务器的消息响应。这用于,例如,在第三方 Cookie 检查期间等待消息。默认值为 10000。
- locale - 当Load 为 'login-required' 时,设置 'ui_locales' 查询参数,以遵守 OIDC 1.0 规范的第 3.1.2.1 部分。
返回初始化完成后解决的承诺。
login (options)
重定向至登录表单。
选项是一个可选对象,其中:
- redirecturi - 指定要在登录后重定向到的 uri。
-
prompt - 此参数允许在红帽构建的 Keycloak 服务器端稍微自定义登录流。例如,在值登录时,强制显示
登录屏幕
。 -
maxAge - 仅在用户已经验证时使用。指定发生用户身份验证后的最长时间。如果用户已经进行身份验证的时间超过
maxAge
的时间,则忽略 SSO,并且需要再次重新进行身份验证。 - loginHint - 用于在登录表单上预先填充 username/email 字段。
-
scope - 覆盖在
init
中配置的范围,其范围使用此特定登录的值不同。 - idpHint - 告知红帽构建的 Keycloak 以跳过显示登录页面,并自动重定向到指定的身份提供程序。如需更多信息,请参阅 身份提供程序文档。
-
acr - 包含有关
acr
声明的信息,该声明将在声明
参数发送到红帽构建的 Keycloak 服务器。典型的用法是进行单步身份验证。使用{ 值的示例: ["silver", "gold"], essential: true }
.如需了解更多详细信息,请参阅 OpenID Connect 规格和步骤 身份验证文档。 -
acrValues - 生成
acr_values
参数,该参数引用身份验证上下文类引用,并允许客户端声明所需的保证级别要求,如验证机制。请参阅 OpenID Connect MODRNA Authentication Profile 1.0 中的第 4 节 cr_values 请求值和保证级别。 -
action - 如果该值是
注册
,则用户将重定向到注册页面。如需了解更多详细信息 ,请参阅 客户端请求的注册部分。如果值为UPDATE_PASSWORD
或另一个支持的必要操作,该用户将重定向到 reset password 页面或其他 required 操作页面。但是,如果用户未通过身份验证,该用户将发送到登录页面并在身份验证后重定向。如需了解更多详细信息,请参阅应用程序初始操作部分。 - locale - 设置"ui_locales"查询参数,使其符合 OIDC 1.0 规范的第 3.1.2.1 部分。
-
cordovaOptions - 指定传递给 Cordova in-app-browser (如果适用)的参数。选择
hidden
和location
不受这些参数的影响。所有可用选项均在 https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-inappbrowser/ 中定义。使用示例:{ zoom: "no", hardwareback: "yes" }
;
createLoginUrl(options)
返回 URL 以登录表单。
选项是一个可选对象,它支持与函数 登录
相同的选项。
logout (options)
重定向 以注销。
选项是一个对象,其中:
- redirecturi - 指定要在退出后重定向到的 uri。
createLogoutUrl(options)
返回 URL 以注销用户。
选项是一个对象,其中:
- redirecturi - 指定要在退出后重定向到的 uri。
register (options)
重定向到注册表单。使用选项操作登录的快捷方式 = 'register'
选项与登录方法相同,但 'action' 被设置为 'register'
createRegisterUrl(options)
返回 url 以注册页面。使用选项 action = 'register' 的 createLoginUrl 的快捷方式
选项与 createLoginUrl 方法相同,但 'action' 设置为 'register'
accountManagement()
重定向到帐户控制台。
createAccountUrl(options)
将 URL 返回到帐户控制台。
选项是一个对象,其中:
- redirecturi - 指定在重定向到应用程序时要重定向到的 uri。
hasRealmRole(role)
如果令牌具有给定域角色,则返回 true。
hasResourceRole (role, resource)
如果令牌具有资源的给定角色(如果没有指定 clientId,则返回 true 是可选的)。
loadUserProfile()
加载 users 配置集。
返回与配置集解析的承诺。
例如:
try { const profile = await keycloak.loadUserProfile(); console.log('Retrieved user profile:', profile); } catch (error) { console.error('Failed to load user profile:', error); }
isTokenExpired(minValidity)
如果令牌在过期前少于 minValidity 秒(使用minValidity 是可选的,则返回 true)。
updateToken(minValidity)
如果令牌在 minValidity 秒内过期(minValidity 是可选的,如果没有指定 5),则刷新令牌。如果 -1 作为 minValidity 传递,则令牌将被强制刷新。如果启用了会话状态 iframe,也会检查会话状态。
返回一个使用布尔值解析的承诺,指示令牌是否已刷新。
例如:
try { const refreshed = await keycloak.updateToken(5); console.log(refreshed ? 'Token was refreshed' : 'Token is still valid'); } catch (error) { console.error('Failed to refresh the token:', error); }
clearToken()
清除身份验证状态,包括令牌。如果应用程序检测到会话已过期,例如更新令牌失败,这很有用。
调用此功能会导致调用 onAuthLogout 回调监听程序。
2.4.9.4. 回调事件
适配器支持为特定事件设置回调监听程序。请记住,必须在调用 init ()
方法之前设置它们。
例如:
keycloak.onAuthSuccess = () => console.log('Authenticated!');
可用的事件有:
- onReady (authenticated) - 当适配器初始化时调用。
- onAuthSuccess - 当用户成功验证时调用。
- onAuthError - 如果身份验证过程中出现错误,则调用。
- onAuthRefreshSuccess - 当令牌被刷新时调用。
- onAuthRefreshError - 如果在尝试刷新令牌时出现错误。
- onAuthLogout - 如果用户已注销(仅在启用会话状态 iframe 或 Cordova 模式时调用)。
- onTokenExpired - 当访问令牌过期时调用。如果一个刷新令牌可用,可以使用 updateToken 刷新令牌,或者在没有(即隐式流)的情况下刷新令牌,您可以重定向到登录屏幕来获取新的访问令牌。