npm install keycloak-js
Keycloak 附带一个名为 keycloak-js
的客户端 JavaScript 库,可用于保护 Web 应用程序的安全。该适配器还内置支持 Cordova 应用程序。该适配器在底层使用 OpenID Connect 协议。您可以查看使用 OpenID Connect 保护应用程序和服务指南,以获取有关 OpenID Connect 端点和功能的更通用信息。
我们建议您从 NPM 安装 keycloak-js
包
npm install keycloak-js
关于使用客户端应用程序,一个重要的考虑事项是客户端必须是公共客户端,因为在客户端应用程序中没有安全的方式来存储客户端凭据。这一考虑使得确保您为客户端配置的重定向 URI 是正确且尽可能具体非常重要。
要使用适配器,请在 Keycloak 管理控制台中为您的应用程序创建一个客户端。通过在能力配置页面上将客户端身份验证切换为关闭,使客户端成为公共客户端。
您还需要配置 Valid Redirect URIs
和 Web Origins
。请尽可能具体,因为未能这样做可能会导致安全漏洞。
以下示例展示了如何初始化适配器。请确保将传递给 Keycloak
构造函数的选项替换为您已配置的客户端的选项。
import Keycloak from 'keycloak-js';
const keycloak = new Keycloak({
url: "http://keycloak-server",
realm: "my-realm",
clientId: "my-app"
});
try {
const authenticated = await keycloak.init();
if (authenticated) {
console.log('User is authenticated');
} else {
console.log('User is not authenticated');
}
} catch (error) {
console.error('Failed to initialize adapter:', error);
}
要进行身份验证,您可以调用 login
函数。有两种选项可以使适配器自动进行身份验证。您可以将 login-required
或 check-sso
传递给 init()
函数。
如果用户已登录 Keycloak,login-required
会对客户端进行身份验证,如果用户未登录,则显示登录页面。
check-sso
仅在用户已登录时对客户端进行身份验证。如果用户未登录,浏览器将重定向回应用程序并保持未身份验证状态。
您可以配置静默 check-sso
选项。启用此功能后,您的浏览器将不会执行到 Keycloak 服务器并返回到您的应用程序的完整重定向,但此操作将在隐藏的 iframe 中执行。因此,您的应用程序资源仅由浏览器加载和解析一次,即在应用程序初始化时,而不是在从 Keycloak 重定向回您的应用程序之后再次加载和解析。这种方法在 SPA(单页应用程序)的情况下尤其有用。
要启用静默 check-sso
,您需要在 init 方法中提供 silentCheckSsoRedirectUri
属性。确保此 URI 是应用程序中的有效端点;它必须在 Keycloak 管理控制台中配置为客户端的有效重定向。
await keycloak.init({
onLoad: 'check-sso',
silentCheckSsoRedirectUri: `${location.origin}/silent-check-sso.html`
});
在成功检查您的身份验证状态并从 Keycloak 服务器检索令牌后,静默 check-sso 重定向 uri 处的页面将在 iframe 中加载。它除了将接收到的令牌发送到主应用程序外,没有其他任务,并且应该只像这样
<!doctype html>
<html>
<body>
<script>
parent.postMessage(location.href, location.origin);
</script>
</body>
</html>
请记住,此页面必须由您的应用程序在 silentCheckSsoRedirectUri
中指定的位置提供,并且不是适配器的一部分。
静默 check-sso 功能在某些现代浏览器中受到限制。请参阅现代浏览器跟踪保护部分。 |
要启用 login-required
,请将 onLoad
设置为 login-required
并传递给 init 方法
await 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();
访问令牌和刷新令牌都存储在内存中,并且不会持久化到任何类型的存储中。因此,永远不应持久化这些令牌,以防止劫持攻击。 |
默认情况下,适配器创建一个隐藏的 iframe,用于检测是否发生了单点注销。此 iframe 不需要任何网络流量。相反,状态是通过查看特殊的状态 cookie 来检索的。可以通过在传递给 init()
方法的选项中设置 checkLoginIframe: false
来禁用此功能。
您不应依赖于直接查看此 cookie。其格式可能会更改,并且它也与 Keycloak 服务器的 URL 相关联,而不是您的应用程序。
会话状态 iframe 功能在某些现代浏览器中受到限制。请参阅现代浏览器跟踪保护部分。 |
默认情况下,适配器使用授权码流程。
使用此流程,Keycloak 服务器返回授权码,而不是身份验证令牌给应用程序。在浏览器重定向回应用程序后,JavaScript 适配器将 code
交换为访问令牌和刷新令牌。
Keycloak 还支持隐式流程,其中在成功通过 Keycloak 身份验证后立即发送访问令牌。与标准流程相比,此流程可能具有更好的性能,因为不存在用于将代码交换为令牌的额外请求,但当访问令牌过期时,它会产生影响。
但是,在 URL 片段中发送访问令牌可能是一个安全漏洞。例如,令牌可能会通过 Web 服务器日志和/或浏览器历史记录泄露。
要启用隐式流程,您需要在 Keycloak 管理控制台中为客户端启用隐式流程已启用标志。您还需要将参数 flow
以及值 implicit
传递给 init
方法
await keycloak.init({
flow: 'implicit'
})
请注意,仅提供访问令牌,并且不存在刷新令牌。这种情况意味着一旦访问令牌过期,应用程序必须再次重定向到 Keycloak 才能获取新的访问令牌。
Keycloak 还支持混合流程。
此流程要求客户端在管理控制台中同时启用标准流程和隐式流程。然后,Keycloak 服务器会将代码和令牌都发送到您的应用程序。访问令牌可以立即使用,而代码可以交换为访问令牌和刷新令牌。与隐式流程类似,混合流程对于性能很有好处,因为访问令牌立即可用。但是,令牌仍然在 URL 中发送,并且前面提到的安全漏洞可能仍然适用。
混合流程的一个优点是刷新令牌可供应用程序使用。
对于混合流程,您需要将参数 flow
以及值 hybrid
传递给 init
方法
await keycloak.init({
flow: 'hybrid'
});
Keycloak 支持使用 Apache Cordova 开发的混合移动应用。该适配器为此有两种模式:cordova
和 cordova-native
默认值为 cordova
,如果没有显式配置适配器类型并且存在 window.cordova
,则适配器会自动选择此模式。登录时,它会打开一个 InApp Browser,允许用户与 Keycloak 交互,然后通过重定向到 https://127.0.0.1
返回到应用程序。由于此行为,您需要将此 URL 列入管理控制台的客户端配置部分的有效重定向 URI 白名单。
虽然此模式易于设置,但它也有一些缺点
InApp-Browser 是嵌入在应用程序中的浏览器,而不是手机的默认浏览器。因此,它将具有不同的设置,并且存储的凭据将不可用。
InApp-Browser 也可能较慢,尤其是在渲染更复杂的主题时。
在使用此模式之前,需要考虑一些安全问题,例如应用程序可能获得用户凭据的访问权限,因为它完全控制了渲染登录页面的浏览器,因此不要在您不信任的应用程序中允许使用它。
另一种模式是 cordova-native
,它采用不同的方法。它使用系统浏览器打开登录页面。用户身份验证后,浏览器使用特殊 URL 重定向回应用程序。从那里,Keycloak 适配器可以通过从 URL 读取代码或令牌来完成登录。
您可以通过将适配器类型 cordova-native
传递给 init()
方法来激活本机模式
await keycloak.init({
adapter: 'cordova-native'
});
此适配器需要两个额外的插件
cordova-plugin-browsertab:允许应用程序在系统浏览器中打开网页
cordova-plugin-deeplinks:允许浏览器通过特殊 URL 重定向回您的应用程序
链接到应用程序的技术细节在每个平台上都不同,并且需要特殊的设置。请参阅 deeplinks 插件文档的 Android 和 iOS 部分,以获取更多说明。
存在不同类型的链接用于打开应用程序
自定义方案,例如 myapp://login
或 android-app://com.example.myapp/https/example.com/login
。
虽然前者更容易设置并且往往更可靠地工作,但后者提供了额外的安全性,因为它们是唯一的,并且只有域的所有者才能注册它们。自定义 URL 在 iOS 上已弃用。为了获得最佳可靠性,我们建议您使用通用链接,并结合使用自定义 URL 链接的后备站点。
此外,我们建议执行以下步骤来提高与适配器的兼容性
iOS 上的通用链接似乎在 response-mode
设置为 query
时更可靠地工作
为防止 Android 在重定向时打开应用程序的新实例,请将以下代码段添加到 config.xml
<preference name="AndroidLaunchMode" value="singleTask" />
在某些情况下,您可能需要在默认不支持的环境中运行适配器,例如 Capacitor。要在这些环境中使用 JavasScript 客户端,您可以传递自定义适配器。例如,第三方库可以提供这样的适配器,使其可以可靠地运行适配器
import Keycloak from 'keycloak-js';
import KeycloakCapacitorAdapter from 'keycloak-capacitor-adapter';
const keycloak = new Keycloak({
url: "http://keycloak-server",
realm: "my-realm",
clientId: "my-app"
});
await 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 = {
async login(options) {
// Write your own implementation here.
}
// The other methods go here...
};
const keycloak = new Keycloak({
url: "http://keycloak-server",
realm: "my-realm",
clientId: "my-app"
});
await keycloak.init({
adapter: MyCustomAdapter,
});
自然,您也可以在没有 TypeScript 的情况下执行此操作,方法是省略类型信息,但确保正确实现接口将完全取决于您自己。
在某些浏览器的最新版本中,应用了各种 cookie 策略来防止第三方跟踪用户,例如 Chrome 中的 SameSite 或完全阻止第三方 cookie。随着时间的推移,这些策略可能会变得更具限制性并被其他浏览器采用。最终,第三方上下文中的 cookie 可能会变得完全不受支持并被浏览器阻止。因此,受影响的适配器功能最终可能会被弃用。
适配器依赖第三方 cookie 来实现会话状态 iframe、静默 check-sso
以及部分用于常规(非静默)check-sso
。这些功能的功能有限或完全禁用,具体取决于浏览器在 cookie 方面的限制程度。适配器尝试检测此设置并做出相应的反应。
会话状态 iframe 不受支持,如果适配器检测到此类浏览器行为,则会自动禁用。这意味着适配器不能使用会话 cookie 进行单点注销检测,而必须纯粹依赖令牌。因此,当用户在另一个窗口中注销时,使用适配器的应用程序在应用程序尝试刷新访问令牌之前不会注销。因此,请考虑将访问令牌生命周期设置为相对较短的时间,以便尽快检测到注销。有关更多详细信息,请参阅会话和令牌超时。
静默 check-sso
不受支持,默认情况下会回退到常规(非静默)check-sso
。可以通过在传递给 init
方法的选项中设置 silentCheckSsoFallback: false
来更改此行为。在这种情况下,如果检测到限制性浏览器行为,check-sso
将被完全禁用。
常规 check-sso
也受到影响。由于会话状态 iframe 不受支持,因此在初始化适配器以检查用户的登录状态时,必须额外重定向到 Keycloak。此检查与标准行为不同,在标准行为中,iframe 用于告知用户是否已登录,并且仅在用户注销时才执行重定向。
受影响的浏览器例如从 13.1 版本开始的 Safari。
// Recommended way to initialize the adapter.
new Keycloak({
url: "http://keycloak-server",
realm: "my-realm",
clientId: "my-app"
});
// Alternatively a string to the path of the `keycloak.json` file.
// Has some performance implications, as it will load the keycloak.json file from the server.
// This version might also change in the future and is therefore not recommended.
new Keycloak("http://keycloak-server/keycloak.json");
如果用户已通过身份验证,则为 true
,否则为 false
。
可以在发送到服务的请求的 Authorization
标头中发送的 base64 编码令牌。
解析后的令牌作为 JavaScript 对象。
用户 ID。
base64 编码的 ID 令牌。
解析后的 id 令牌作为 JavaScript 对象。
与令牌关联的 realm 角色。
与令牌关联的资源角色。
可用于检索新令牌的 base64 编码刷新令牌。
解析后的刷新令牌作为 JavaScript 对象。
浏览器时间和 Keycloak 服务器之间估计的时间差(以秒为单位)。此值仅为估计值,但在确定令牌是否过期时足够准确。
在 init 中传递的响应模式(默认值为 fragment)。
在 init 中传递的流程。
允许您覆盖库处理重定向和其他浏览器相关功能的方式。可用选项
“default” - 库使用浏览器 API 进行重定向(这是默认值)
“cordova” - 库将尝试使用 InAppBrowser cordova 插件加载 keycloak 登录/注册页面(当库在 cordova 生态系统中工作时,会自动使用此选项)
“cordova-native” - 库尝试使用 BrowserTabs cordova 插件打开手机系统浏览器中的登录和注册页面。这需要额外的设置才能重定向回应用程序(请参阅 使用 Cordova 的混合应用)。
“custom” - 允许您实现自定义适配器(仅适用于高级用例)
随登录请求发送到 Keycloak 的响应类型。这根据初始化期间使用的 flow 值确定,但可以通过设置此值来覆盖。
init(options)
调用以初始化适配器。
Options 是一个对象,其中
useNonce - 添加加密 nonce 以验证身份验证响应是否与请求匹配(默认值为 true
)。
onLoad - 指定加载时要执行的操作。支持的值为 login-required
或 check-sso
。
silentCheckSsoRedirectUri - 如果 onLoad 设置为 'check-sso',则设置静默身份验证检查的重定向 uri。
silentCheckSsoFallback - 当浏览器不支持静默 check-sso
时,启用回退到常规 check-sso
(默认值为 true
)。
token - 为令牌设置初始值。
refreshToken - 为刷新令牌设置初始值。
idToken - 为 id 令牌设置初始值(仅与令牌或 refreshToken 一起使用)。
scope - 为 Keycloak 登录端点设置默认 scope 参数。使用空格分隔的 scope 列表。这些通常引用在特定客户端上定义的客户端 scope。请注意,scope openid
将始终由适配器添加到 scope 列表中。例如,如果您输入 scope 选项 address phone
,则对 Keycloak 的请求将包含 scope 参数 scope=openid address phone
。请注意,如果 login()
选项显式指定 scope,则此处指定的默认 scope 将被覆盖。
timeSkew - 以秒为单位设置本地时间和 Keycloak 服务器之间偏差的初始值(仅与令牌或 refreshToken 一起使用)。
checkLoginIframe - 设置为启用/禁用监视登录状态(默认值为 true
)。
checkLoginIframeInterval - 设置检查登录状态的间隔(默认值为 5 秒)。
responseMode - 设置在登录请求时发送到 Keycloak 服务器的 OpenID Connect 响应模式。有效值为 query
或 fragment
。默认值为 fragment
,这意味着成功身份验证后,Keycloak 将使用 URL 片段中添加的 OpenID Connect 参数重定向到 JavaScript 应用程序。这通常比 query
更安全且更推荐。
flow - 设置 OpenID Connect 流程。有效值为 standard
、implicit
或 hybrid
。
enableLogging - 启用从 Keycloak 到控制台的日志消息(默认值为 false
)。
pkceMethod - 用于 Proof Key Code Exchange (PKCE) 的方法。配置此值会启用 PKCE 机制。可用选项
“S256” - 基于 SHA256 的 PKCE 方法(默认)
false - 禁用 PKCE。
acrValues - 生成 acr_values
参数,该参数引用身份验证上下文类引用,并允许客户端声明所需的保证级别要求,例如身份验证机制。请参阅 OpenID Connect MODRNA 身份验证配置文件 1.0 中的第 4 节 acr_values 请求值和保证级别。
messageReceiveTimeout - 设置等待来自 Keycloak 服务器的消息响应的超时时间(以毫秒为单位)。例如,这用于在等待第三方 cookie 检查期间的消息时。默认值为 10000。
locale - 当 onLoad 为 'login-required' 时,根据 OIDC 1.0 规范的第 3.1.2.1 节设置 'ui_locales' 查询参数。
返回在初始化完成时解析的 promise。
login(options)
重定向到登录表单,返回 Promise。
Options 是一个可选对象,其中
redirectUri - 指定登录后要重定向到的 uri。
prompt - 此参数允许稍微自定义 Keycloak 服务器端的登录流程。例如,对于值 login
,强制显示登录屏幕。或者对于客户端具有 Consent Required
的情况,强制显示同意屏幕以获取值 consent
。最后,可以使用值 none
来确保不向用户显示登录屏幕,这仅在用户之前已通过身份验证的情况下检查 SSO 时才有用(这与上面描述的具有值 check-sso
的 onLoad
检查相关)。
maxAge - 仅在用户已通过身份验证时使用。指定自用户身份验证发生以来的最长时间。如果用户已通过身份验证的时间超过 maxAge
,则 SSO 将被忽略,并且他将需要重新进行身份验证。
loginHint - 用于预填充登录表单上的用户名/电子邮件字段。
scope - 使用此特定登录的不同值覆盖在 init
中配置的 scope。
idpHint - 用于告诉 Keycloak 跳过显示登录页面并自动重定向到指定的身份提供程序。更多信息请参见身份提供程序文档。
acr - 包含有关 acr
声明的信息,该信息将作为 claims
参数发送到 Keycloak 服务器。典型用法是用于逐步身份验证。使用示例 { values: ["silver", "gold"], essential: true }
。有关更多详细信息,请参阅 OpenID Connect 规范和 逐步身份验证文档。
acrValues - 生成 acr_values
参数,该参数引用身份验证上下文类引用,并允许客户端声明所需的保证级别要求,例如身份验证机制。请参阅 OpenID Connect MODRNA 身份验证配置文件 1.0 中的第 4 节 acr_values 请求值和保证级别。
action - 如果值为 register
,则用户将被重定向到注册页面。有关更多详细信息,请参阅客户端请求的注册部分。如果值为 UPDATE_PASSWORD
或另一个受支持的必需操作,则用户将被重定向到重置密码页面或其他必需操作页面。但是,如果用户未通过身份验证,则用户将被发送到登录页面,并在身份验证后重定向。有关更多详细信息,请参阅应用程序启动的操作部分。
locale - 根据 OIDC 1.0 规范的第 3.1.2.1 节设置 'ui_locales' 查询参数。
cordovaOptions - 指定传递给 Cordova 应用内浏览器(如果适用)的参数。选项 hidden
和 location
不受这些参数的影响。所有可用选项都在 https://cordova.net.cn/docs/en/latest/reference/cordova-plugin-inappbrowser/ 中定义。使用示例:{ zoom: "no", hardwareback: "yes" }
;
createLoginUrl(options)
返回包含登录表单 URL 的 Promise。
Options 是一个可选对象,它支持与函数 login
相同的选项。
logout(options)
重定向到注销。
Options 是一个对象,其中
redirectUri - 指定注销后要重定向到的 uri。
createLogoutUrl(options)
返回注销用户的 URL。
Options 是一个对象,其中
redirectUri - 指定注销后要重定向到的 uri。
register(options)
重定向到注册表单。login 的快捷方式,选项 action = 'register'
Options 与 login 方法相同,但 'action' 设置为 'register'
createRegisterUrl(options)
返回包含注册页面 url 的 Promise。createLoginUrl 的快捷方式,选项 action = 'register'
Options 与 createLoginUrl 方法相同,但 'action' 设置为 'register'
accountManagement()
重定向到帐户控制台。
createAccountUrl(options)
返回帐户控制台的 URL。
Options 是一个对象,其中
redirectUri - 指定重定向回应用程序时要重定向到的 uri。
hasRealmRole(role)
如果令牌具有给定的 realm 角色,则返回 true。
hasResourceRole(role, resource)
如果令牌对资源具有给定的角色,则返回 true(resource 是可选的,如果未指定,则使用 clientId)。
loadUserProfile()
加载用户个人资料。
返回解析为个人资料的 promise。
例如
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 秒,则返回 true(minValidity 是可选的,如果未指定,则使用 0)。
updateToken(minValidity)
如果令牌在 minValidity 秒内过期(minValidity 是可选的,如果未指定,则使用 5),则刷新令牌。如果传递 -1 作为 minValidity,则将强制刷新令牌。如果启用了会话状态 iframe,则还会检查会话状态。
返回一个 promise,该 promise 解析为一个布尔值,指示令牌是否已刷新。
例如
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 回调侦听器。
适配器支持为某些事件设置回调侦听器。请记住,这些必须在调用 init()
方法之前设置。
例如
keycloak.onAuthSuccess = () => console.log('Authenticated!');
可用的事件有
onReady(authenticated) - 在适配器初始化时调用。
onAuthSuccess - 在用户成功通过身份验证时调用。
onAuthError - 如果在身份验证期间发生错误,则调用。
onAuthRefreshSuccess - 在令牌刷新时调用。
onAuthRefreshError - 如果在尝试刷新令牌时发生错误,则调用。
onAuthLogout - 如果用户注销,则调用(仅在启用会话状态 iframe 或在 Cordova 模式下调用)。
onTokenExpired - 在访问令牌过期时调用。如果刷新令牌可用,则可以使用 updateToken 刷新令牌,或者在刷新令牌不可用的情况下(即使用隐式流程),您可以重定向到登录屏幕以获取新的访问令牌。