You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Keycloak-Connect/Express中间件令牌验证失败排查求助

问题

前端客户端通过keycloak-js完成Keycloak认证后,将获取到的keycloak.token以Bearer令牌形式转发至Node.js/Express/keycloak-connect后端,但后端令牌验证失败,返回HTTP 403 Forbidden错误。已确认前后端属于同一Realm,令牌有效期、aud/iss/sub字段均匹配,角色也已配置,但仍无法定位失败原因,且未找到keycloak中间件的调试钩子追踪验证过程。

服务端代码

keycloak.ts

// @ts-ignore
import Keycloak from "keycloak-connect"
// @ts-ignore
import session from "express-session"

let _keycloak: Keycloak.Keycloak | undefined = undefined;
const memoryStore = new session.MemoryStore();

export function getKeycloak(): Keycloak.Keycloak {
    if (!_keycloak) {
      _keycloak = new Keycloak({ store: memoryStore }, {
        "realm": "ear",
        "bearer-only": true,
        "auth-server-url": "http://192.168.76.4:40002/auth/",
        "ssl-required": "external",
        "resource": "ear-backend",
        "confidential-port": 0
      }); }
    return _keycloak;
}

server.ts

import {getKeycloak} from "./keycloak";
import express from "express";
import {Request,Response} from "express";
// @ts-ignore
import cors from "cors";

var app = express();
app.use(cors());
var router = express.Router();
router.get('/user', getKeycloak().protect(), function(req, res){ res.send("Hello User");});
app.use("/test", router);
app.listen(3001);

前端转发的Bearer令牌

authorization: 'Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJkaDEweTB2WWhnUFVmcWppQVZ3ZVBXUUxTYmpxUWVkaWprZHFBMUVLbUdJIn0.eyJleHAiOjE2NzQzODM5NjgsImlhdCI6MTY3NDM4MzY2OCwiYXV0aF90aW1lIjoxNjc0MzgzNjY4LCJqdGkiOiJmYjhjMTJkMy0xMmFmLTQ1M2MtYmE1Mi0yNzA3ZDkwYTNkMDEiLCJpc3MiOiJodHRwOi8vMTkyLjE2OC43Ni40OjQwMDAyL2F1dGgvcmVhbG1zL2VhciIsImF1ZCI6ImVhci1iYWNrZW5kIiwic3ViIjoiMDQxNTY1ZDQtYzM0Ni00MDRmLWFmYzYtMjVjMzRmMGViNWM5IiwidHlwIjoiQmVhcmVyIiwiYXpwIjoiZWFyLWZyb250ZW5kIiwibm9uY2UiOiI2ZGUzOGYzMy00MmQyLTQ4ZTItODQwMi01M2I4OTViNzc4Y2YiLCJzZXNzaW9uX3N0YXRlIjoiYTEyYzhkY2ItMjk5Yy00Y2VlLWEyYWQtOThkN2M1MDJkMDgzIiwiYWNrIjoidXNlciAxMiIsInByZWZlcnJlZF91c2VybmFtZSI6InVzZXIxMiIsImdpdmVuX25hbWUiOiJVc2VyIiwiZmFtaWx5X25hbWUiOiIxMiIsImVtYWlsIjoidXNlci4xMkBhY21lLmNvbSJ9.U8YRbUuOdSPKfDeUIfAb5r12ZGhaTB-GCspY9RjKW8iMn2btbTDd9v9TQAvFbvgHHQ7F0QOtwZvfgWDludO1H3pUiEuhzkRcrw7NQLN4WY3atUrIEACpMa5pthZXzDzia3VBYlChMZPnsMOCAq5-fhULhjYz-4SY6YrTpL5TcDcCuAj28-CZt00hqxGQvd2q-LCpRuFXQ6GnxV0fYJZVtX_yolTAJAVHph7uG_WxgBqpxqdh9QBQ1av3Jn9yElo9qZjzbaD261WR1sae6idkSdLmZai1c7r9zVl9MDw8_qE8tzuaY20gIOG2HpUS4sqW7oM9I5cwMBKCHOzODpXkZg'

排查方向与解决方案

  • 开启调试日志定位失败细节:
    在Keycloak初始化配置中添加logLevel: 'debug',或启动后端时设置环境变量DEBUG=keycloak-connect*,可输出令牌验证全流程日志,包括签名验证、角色检查、证书获取等步骤的具体错误信息。

  • 修正SSL配置冲突:
    后端配置ssl-required: "external"要求外部请求使用HTTPS,但当前Keycloak服务为HTTP协议,且后端运行在本地环境,将该配置改为ssl-required: "none"即可解决环境不匹配问题。

  • 移除bearer-only模式下的Session存储:
    bearer-only模式为无状态令牌验证,无需Session存储支持,初始化Keycloak时移除store: memoryStore参数,避免Session机制干扰验证流程:

    _keycloak = new Keycloak({}, {
      "realm": "ear",
      "bearer-only": true,
      "auth-server-url": "http://192.168.76.4:40002/auth/",
      "ssl-required": "none",
      "resource": "ear-backend",
      "confidential-port": 0
    });
    
  • 验证令牌角色与保护规则匹配:
    getKeycloak().protect()默认检查用户是否拥有后端客户端(ear-backend)的角色,需确认:

    1. 用户已被分配ear-backend客户端的对应角色;
    2. 令牌的resource_access.ear-backend.roles字段包含该角色;
      若需使用Realm层面角色,可改为getKeycloak().protect('realm:user')(替换为实际Realm角色名)。
  • 检查Keycloak公钥可达性:
    后端需从Keycloak的/auth/realms/ear/protocol/openid-connect/certs端点获取公钥验证令牌签名,确保后端服务器能正常访问该端点,无网络防火墙或代理拦截。

内容的提问来源于stack exchange,提问作者user1351376

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 01:05:18