创建浏览器用户通行密钥时出错

当我尝试在自己的网站上创建通行密钥时,它会提示:

通行密钥注册过程超时、被取消或不允许

但是,我可以在同一个浏览器(Microsoft Edge)和同一个插件(Apple Passkey)的 Discourse Meta 论坛中创建通行密钥。

我已经将 Discourse 升级到最新版本,但它不像这篇文章那样工作。

嘿,看起来当您分享的这条消息出现在对话框中时,我们会显示一个控制台错误

您能否打开浏览器控制台,与我们分享您可能看到的错误?


日志中似乎没有关于此错误的任何信息

您需要查看您的浏览器控制台日志,而不是网站 /logs。

这个对吗?

forum.beginner.center/:1  混合内容:页面“https://forum.beginner.center/”通过 HTTPS 加载,但请求了一个不安全的字体“http://forum.beginner.center/fonts/JetBrainsMono-Regular.woff2?v=0.0.19”。此请求已被阻止;内容必须通过 HTTPS 提供。
forum.beginner.center/:1  混合内容:页面“https://forum.beginner.center/”通过 HTTPS 加载,但请求了一个不安全的字体“http://forum.beginner.center/fonts/JetBrainsMono-Bold.woff2?v=0.0.19”。此请求已被阻止;内容必须通过 HTTPS 提供。
app.js:270 ℹ️ Discourse v3.5.0.beta9-dev — https://github.com/discourse/discourse/commits/33dfd7dba9 — Ember v5.12.0
[仅报告] 因以下内容安全策略指令:“script-src 'nonce-4YvvTZffYuqGaENC8DnQ7yeNg' 'strict-dynamic'”不允许“unsafe-eval”作为脚本源,而拒绝将字符串评估为 JavaScript。

[仅报告] 因以下内容安全策略指令:“script-src 'nonce-4YvvTZffYuqGaENC8DnQ7yeNg' 'strict-dynamic'”不允许“unsafe-eval”作为脚本源,而拒绝将字符串评估为 JavaScript。

[仅报告] 因以下内容安全策略指令:“script-src 'nonce-4YvvTZffYuqGaENC8DnQ7yeNg' 'strict-dynamic'”不允许“unsafe-eval”作为脚本源,而拒绝将字符串评估为 JavaScript。

[仅报告] 因以下内容安全策略指令:“script-src 'nonce-4YvvTZffYuqGaENC8DnQ7yeNg' 'strict-dynamic'”不允许“unsafe-eval”作为脚本源,而拒绝将字符串评估为 JavaScript。

[仅报告] 因以下内容安全策略指令:“script-src 'nonce-4YvvTZffYuqGaENC8DnQ7yeNg' 'strict-dynamic'”不允许“unsafe-eval”作为脚本源,而拒绝将字符串评估为 JavaScript。

[仅报告] 因以下内容安全策略指令:“script-src 'nonce-4YvvTZffYuqGaENC8DnQ7yeNg' 'strict-dynamic'”不允许“unsafe-eval”作为脚本源,而拒绝将字符串评估为 JavaScript。

[仅报告] 因以下内容安全策略指令:“script-src 'nonce-4YvvTZffYuqGaENC8DnQ7yeNg' 'strict-dynamic'”不允许“unsafe-eval”作为脚本源,而拒绝将字符串评估为 JavaScript。

[仅报告] 因以下内容安全策略指令:“script-src 'nonce-4YvvTZffYuqGaENC8DnQ7yeNg' 'strict-dynamic'”不允许“unsafe-eval”作为脚本源,而拒绝将字符串评估为 JavaScript。

[仅报告] 因以下内容安全策略指令:“script-src 'nonce-4YvvTZffYuqGaENC8DnQ7yeNg' 'strict-dynamic'”不允许“unsafe-eval”作为脚本源,而拒绝将字符串评估为 JavaScript。

analytics.eu.umami.is/script.js:1   加载资源失败:net::ERR_CONNECTION_CLOSED
跟踪防护阻止了对 <URL> 的存储的访问。
跟踪防护阻止了对 <URL> 的存储的访问。
跟踪防护阻止了对 <URL> 的存储的访问。
跟踪防护阻止了对 <URL> 的存储的访问。
跟踪防护阻止了对 <URL> 的存储的访问。
跟踪防护阻止了对 <URL> 的存储的访问。
跟踪防护阻止了对 <URL> 的存储的访问。
跟踪防护阻止了对 <URL> 的存储的访问。
跟踪防护阻止了对 <URL> 的存储的访问。
跟踪防护阻止了对 <URL> 的存储的访问。
跟踪防护阻止了对 <URL> 的存储的访问。
跟踪防护阻止了对 <URL> 的存储的访问。
跟踪防护阻止了对 <URL> 的存储的访问。
跟踪防护阻止了对 <URL> 的存储的访问。
跟踪防护阻止了对 <URL> 的存储的访问。
跟踪防护阻止了对 <URL> 的存储的访问。
deprecated.js:62  弃用通知:设置用户对象的 timezone 属性已被弃用。请改用 user_option 对象 [自 Discourse 2.9.0.beta12 起弃用] [将在 Discourse 3.0.0.beta1 中移除] [弃用 ID:discourse.user.userOptions]
a @ deprecated.js:62
security:1 自动对焦处理被阻止,因为文档已有一个聚焦的元素。
completion_list.html:14   GET chrome-extension://mfbcdcnpokpoajjciilocoachedjkima/heuristicsRedefinitions.js net::ERR_FILE_NOT_FOUND
completion_list.html:13   GET chrome-extension://mfbcdcnpokpoajjciilocoachedjkima/extensionState.js net::ERR_FILE_NOT_FOUND
completion_list.html:12   GET chrome-extension://mfbcdcnpokpoajjciilocoachedjkima/utils.js net::ERR_FILE_NOT_FOUND
ajax.js:188   POST https://forum.beginner.center/u/register_passkey.json 401 (未授权)
send @ jquery.js:9940
ajax @ jquery.js:9521
o @ ajax.js:188
(匿名) @ rsvp-DaQAFb0W.js:435
e @ rsvp-DaQAFb0W.js:451
A @ ajax.js:201
registerPasskey @ user.js:650
createPasskey @ user-passkeys.gjs:86
await in createPasskey
didConfirm @ user-passkeys.gjs:140
didConfirmWrapped @ dialog.js:134
_join @ index.js:788
join @ index.js:605
p @ index.js:152
(匿名) @ index.js:250
submit @ confirm-session.gjs:84
await in submit
(匿名) @ d-button.gjs:138
invoke @ index.js:264
flush @ index.js:180
flush @ index.js:334
_end @ index.js:762
end @ index.js:565
_runExpiredTimers @ index.js:869
setTimeout
setTimeout @ index.js:39
_installTimerTimeout @ index.js:912
_later @ index.js:823
later @ index.js:652
T @ index.js:562
_triggerAction @ d-button.gjs:135
click @ d-button.gjs:93
user-passkeys.gjs:104  {jqXHR: {…}, textStatus: 'error', errorThrown: ''}errorThrown: \"\"jqXHR: abort: ƒ (e)always: ƒ ()catch: ƒ (e)done: ƒ ()fail: ƒ ()getAllResponseHeaders: ƒ ()getResponseHeader: ƒ (e)jqTextStatus: \"error\"overrideMimeType: ƒ (e)pipe: ƒ ()progress: ƒ ()promise: ƒ (e)readyState: 4requestedUrl: \"/u/register_passkey.json\"responseJSON: {errors: Array(1)}responseText: \"{\\\"errors\\\":[\\\"The origin of the authentication request does not match the server origin.\\\"]}\"setRequestHeader: ƒ (e,t)state: ƒ ()status: 401statusCode: ƒ (e)statusText: \"error\"then: ƒ (e,i,n)[[Prototype]]: ObjecttextStatus: \"error\"[[Prototype]]: Objectconstructor: ƒ Object()hasOwnProperty: ƒ hasOwnProperty()isPrototypeOf: ƒ isPrototypeOf()propertyIsEnumerable: ƒ propertyIsEnumerable()toLocaleString: ƒ toLocaleString()toString: ƒ toString()valueOf: ƒ valueOf()__defineGetter__: ƒ __defineGetter__()__defineSetter__: ƒ __defineSetter__()__lookupGetter__: ƒ __lookupGetter__()__lookupSetter__: ƒ __lookupSetter__()__proto__: (...)get __proto__: ƒ __proto__()set __proto__: ƒ __proto__()
createPasskey @ user-passkeys.gjs:104
await in createPasskey
didConfirm @ user-passkeys.gjs:140
didConfirmWrapped @ dialog.js:134
_join @ index.js:788
join @ index.js:605
p @ index.js:152
(匿名) @ index.js:250
submit @ confirm-session.gjs:84
await in submit
(匿名) @ d-button.gjs:138
invoke @ index.js:264
flush @ index.js:180
flush @ index.js:334
_end @ index.js:762
end @ index.js:565
_runExpiredTimers @ index.js:869
setTimeout
setTimeout @ index.js:39
_installTimerTimeout @ index.js:912
_later @ index.js:823
later @ index.js:652
T @ index.js:562
_triggerAction @ d-button.gjs:135
click @ d-button.gjs:93
1 个赞

哦,嗯,这很有用,但 401 可能由多种原因触发。我会与我们专门研究 passkey 的专家核实。

1 个赞

请确保您的网站已配置为通过 https 提供所有内容。Passkey 挑战验证要求所有请求都通过 https 进行。此外,浏览器和服务器之间的域名必须完全匹配。如果任何地方存在不匹配,验证都会失败。

我们有一个为此设置的选项 force_https,您可以尝试一下,这可能会有帮助(但请小心,如果服务器配置不当,它也可能导致您被锁定)。

2 个赞

这是我的 app.yml
我正在使用 OpenResty(基于 nginx)作为反向代理

expose:
  - "6180:80"   # http
  - "6443:443" # https
  - "587:587"

我无法通过 https 端口 6443 访问我的网站

所以我只设置了 http 的反向代理

这是我的 OpenResty 配置

server {
    listen 80 ;
    listen 443 ssl http2 ;
    server_name forum.beginner.center;
    index index.php index.html index.htm default.php default.htm default.html;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Host $server_name;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $http_connection;
    access_log /www/sites/forum.beginner.center/log/access.log main;
    error_log /www/sites/forum.beginner.center/log/error.log;
    location ^~ /.well-known/acme-challenge {
        allow all;
        root /usr/share/nginx/html;
    }
    if ($scheme = http) {
        return 301 https://$host$request_uri;
    }
    ssl_certificate /www/sites/forum.beginner.center/ssl/fullchain.pem;
    ssl_certificate_key /www/sites/forum.beginner.center/ssl/privkey.pem;
    ssl_protocols TLSv1.3 TLSv1.2 TLSv1.1 TLSv1;
    ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:!aNULL:!eNULL:!EXPORT:!DSS:!DES:!RC4:!3DES:!MD5:!PSK:!KRB5:!SRP:!CAMELLIA:!SEED;
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    error_page 497 https://$host$request_uri;
    proxy_set_header X-Forwarded-Proto https;
    add_header Strict-Transport-Security "max-age=31536000";
    include /www/sites/forum.beginner.center/proxy/*.conf;
}

这是反向代理配置

location ^~ / {
    proxy_pass http://127.0.0.1:6180;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header REMOTE-HOST $remote_addr;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $http_connection;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_http_version 1.1;
    add_header X-Cache $upstream_cache_status;
    add_header Cache-Control no-cache;
    proxy_ssl_server_name off;
    proxy_ssl_name $proxy_host;
    add_header Strict-Transport-Security "max-age=31536000";
}

你好,有人能帮帮我吗?

抱歉延迟回复。您这里的问题确实与您的代理服务器有关。我无法确切说明是哪个环节出了问题,但域名、协议(http 或 https)和端口中的一个似乎存在冲突。

Passkeys 会验证前端和后端是否运行在相同的域名、协议和端口上。如果其中任何一个不匹配,您就会收到类似这样的错误。

在 Rails CLI 中,您可以尝试运行:

DiscourseWebauthn.origin

然后将其与您在浏览器中访问站点的 URL 进行比较?两者应该匹配。

user passkey function 在启用 force https 时可以正常工作

参考

2 个赞

据我所理解的 Webauthn 标准(用于 Passkey),它依赖于信赖方(Discourse)与客户端(浏览器或移动设备)以及身份验证器(例如 Yubikey)之间的安全连接。因此,我们需要 https 来进行来自 Discourse 应用程序的通信。强制使用 https 可能是解决方案,但仅通过以下标头:

proxy_set_header X-Forwarded-Proto https;

也可能足够。如果强制使用 https 有帮助(这无论如何都是推荐的),那么一切都会好起来。

1 个赞

我不知道如何在 app.yaml 中配置 proxy_set_header X-Forwarded-Proto