java - WebAuthn:无法在子域上登录
问题描述
我有一个 Angular 11(前端)和 Kotlin(后端)项目,我在其中实现了 WebAuthn 登录。
注册工作很简单,我从 (WebAuthn4J) 后端收到挑战,并使用以下内容创建凭据:
...
const credentialOptions: CredentialCreationOptions = {
publicKey: {
attestation: 'direct',
user: {
name: 'UsernameXYZ',
displayName: 'UsernameXYZ',
id: decodeUrlSafeB64(btoa('<uuid-from-db>'))
},
rp: {
id: 'my-company.com',
name: 'My Company'
},
challenge: challenge, // Challenge from Backend as B64
pubKeyCredParams: [
{
type: 'public-key',
alg: -257 // RS256
},
{
type: 'public-key',
alg: -7 // ES256
}
],
authenticatorSelection: undefined // All options possible
}
};
const credentials: Credential = await navigator.credentials.create(credentialOptions);
...
现在,我可以毫无问题地登录my-company.com
。但我无法 登录,other.my-company.com
我不明白为什么。WebAuthn 对话(来自 Win10)显示“无法识别身份验证器”(不完全正确,因为消息是德语)。
我所做的只是将有效的 credentialIds(我从后端收到)交给导航器。
...
const credIds: Array<PublicKeyCredentialDescriptor> = [];
credentialIds.forEach((credentialId) => {
credIds.push({
type: 'public-key',
id: decodeUrlSafeB64(credentialId)
});
});
// my-company.com --> WebAuthn Dialog as expected
// other.my-company.com --> WebAuthnDialog does not recognize key
navigator.credentials.get({
publicKey: {
challenge: challenge, // Challenge for Login from Backend
allowCredentials: credIds,
userVerification: 'preferred'
}
});
...
但是,当我通过以下方式进行注册other.my-company.com
时:
rp: {
id: 'other.my-company.com',
name: 'My Company'
},
我现在可以从my-company.com
AND登录other.my-company.com
。这适用于我现在的设置,但是当我计划扩展我的项目并在another.my-company.com
此登录时将无法正常工作。
我阅读了规范,虽然我认为它相当普遍,但它对这个设置非常不具体:https ://www.w3.org/TR/webauthn/#relying-party-identifier
在一个类似的 SO question 中,它说我在这里的设置应该可以工作(虽然没有任何来源):WebAuthn across multiple subdomain
我在实现逻辑时也遵循了这一点:https ://developer.mozilla.org/en-US/docs/Web/API/Web_Authentication_API
我不知道在哪里研究。我使用的 WebAuthn4J 实现(https://github.com/webauthn4j/webauthn4j)工作得很好,证明我可以从上面的两个设置中登录。
我想出的唯一其他选择是将整个登录/注册过程与应用程序的其余部分分开,以便每次登录都重定向到sso.my-company.com
,使用 WebAuthn 登录,获取 JWT 并重定向回原始应用程序。但这真的是我唯一的选择吗?对于我想要做的事情,即“注册域并允许所有子域”,这似乎太过分了。
任何提示(甚至只指向我链接的其他规格)
解决方案
您需要在断言期间将RP ID设置为创建期间使用的相同 RP ID。如果您不设置它,它将默认为当前来源并包含子域,因此它将不再匹配。
推荐阅读
- sql - 在 BigQuery 中格式化电话号码
- sql - VBA 日期时间格式并导入到 sql
- react-native - React Native 中构造函数的返回类型
- node.js - 如何从我的数据库中获取我的数据作为变量?
- c++ - QLine 未添加到所有 QCharts
- java - gRPC 客户端如何知道网络丢失/故障?
- c++ - RValue 引用的大小是多少?
- matlab - 碰撞问题:将圆弧的旋转中心放在一个半圆上并旋转它直到它接触到它所在的半圆
- reactjs - 我们如何在 antd 中根据 jsx 条件和数组索引添加元素
- javascript - 以更短的方式替换下面的 if、else-if、else