Mercure更换JWT密钥后Vue订阅端报401 Unauthorized问题求助
Mercure更换JWT密钥后前端订阅返回401排查方案
按以下优先级从高到低排查,90%的场景都是前两个问题导致的:
- 确认JWT签名匹配问题
Postman推送正常只能证明你用的发布端token和MERCURE_PUBLISHER_JWT_KEY匹配,和订阅端鉴权无关。换密钥后必须用新的MERCURE_SUBSCRIBER_JWT_KEY重新生成前端订阅用的JWT,之前用默认值!ChangeMe!签的旧token会直接验签失败。
额外注意docker-compose的环境变量转义坑:如果新密钥带!、$、&这类yaml或者shell的特殊字符,没正确用引号包裹的话,容器里实际加载的密钥和你写在配置里的根本不是同一个。可以进容器执行命令校验实际生效的密钥:
如果输出值和你配置的不一致,给密钥加双引号包裹,或者换个不带特殊字符的密钥,也可以用docker secret传密钥规避转义问题。docker exec 你的mercure容器名 env | grep MERCURE_JWT_KEY - 修正前端EventSource的错误写法
浏览器原生EventSourceAPI根本不支持自定义请求头,你代码里写的headers配置项会被直接忽略,请求根本不会带mercureAuthorization这个头。
之前默认密钥下能连上,是因为当时配置没触发强制订阅鉴权,走了匿名访问;换密钥后鉴权生效,请求没带有效token直接被拦了返回401。
修复方法很简单,把订阅JWT作为access_token查询参数拼到URL里就行,修正后的代码:
同域部署场景也可以用Cookie传鉴权凭证,只要在Mercure额外配置里把const url = new URL("https://localhost/.well-known/mercure"); url.searchParams.append("topic", "chat"); // 这里填你用新订阅密钥重新生成的有效JWT url.searchParams.append("access_token", "新生成的订阅JWT"); const eventSource = new EventSource(url); eventSource.onmessage = (event) => { this.$notify({ type: "success", text: "push", }); console.log(event); };cors_origins、cookie_same_site配成和你前端域名匹配就行,这种方式不会把token暴露在URL里,安全性更高。 - 校验JWT的权限声明
如果前面两个问题都排除了还是401,检查你生成的订阅JWT的payload,必须包含对应topic的订阅权限,正确格式参考:
哪怕签名是对的,没有配置对应topic的订阅权限,一样会返回401。{ "mercure": { "subscribe": ["chat"] }, "exp": 1735689600 }
内容的提问来源于stack exchange,提问作者Vortex666
相关产品推荐
相关产品推荐

