如何在Node.js Express API中验证React SPA从Keycloak获取的访问令牌
Express后端校验Keycloak访问令牌的缺失步骤整理
1. 安装对应依赖
你可以选择Keycloak官方适配的中间件,或者通用JWT校验库,对应安装命令如下:
- 官方keycloak-connect方案:
npm install keycloak-connect - 通用JWT手动校验方案:
npm install jsonwebtoken
2. 准备Keycloak校验必要配置
你需要提前从Keycloak控制台获取以下信息,用于后续校验:
- 所属Realm的RS256公钥(获取路径:Realm设置→密钥→选中RS256算法对应的公钥)
- Realm的issuer地址,格式为
https://<你的Keycloak域名>/realms/<你的Realm名称> - 对应客户端的ID(即前端申请令牌时使用的client_id)
- 若使用官方中间件,可直接下载
keycloak.json配置文件放到后端项目根目录,需把配置中的bearer-only属性设为true,适配后端API无登录页的无状态场景
3. 前端请求适配
需确保前端发起API请求时,将获取到的访问令牌放在Authorization请求头中,格式为:
Authorization: Bearer <你拿到的access_token字符串>
如果配置了跨域,需要在Express的CORS配置中允许Authorization请求头,避免被浏览器拦截。
4. 后端实现校验逻辑
方案A:使用官方keycloak-connect中间件(推荐)
初始化中间件并挂载到需要保护的路由即可,示例代码:
const Keycloak = require('keycloak-connect'); const express = require('express'); const app = express(); // 无状态API可以不传session配置直接初始化 const keycloak = new Keycloak({}); app.use(keycloak.middleware()); // 受保护的路由添加keycloak.protect()中间件即可自动校验令牌 app.get('/api/protected/data', keycloak.protect(), (req, res) => { // 校验通过后可从req.kauth.grant中获取用户信息 res.json({ data: '敏感数据', user: req.kauth.grant.access_token.content }); });
方案B:手动实现JWT校验逻辑
如果不想引入完整的Keycloak中间件,可以自己实现校验中间件,示例代码:
const jwt = require('jsonwebtoken'); const express = require('express'); const app = express(); // 替换为你自己的Keycloak配置 const KEYCLOAK_PUBLIC_KEY = `-----BEGIN PUBLIC KEY----- 你从控制台复制的公钥内容 -----END PUBLIC KEY-----`; const KEYCLOAK_ISSUER = 'https://你的Keycloak域名/realms/你的Realm名称'; const CLIENT_ID = '你的客户端ID'; // 自定义校验中间件 const validateKeycloakToken = (req, res, next) => { const authHeader = req.headers.authorization; // 校验请求头是否携带符合格式的令牌 if (!authHeader?.startsWith('Bearer ')) { return res.status(401).json({ error: '缺少有效访问令牌' }); } const token = authHeader.split(' ')[1]; try { // 校验签名、有效期、发行方、受众 const decodedToken = jwt.verify(token, KEYCLOAK_PUBLIC_KEY, { issuer: KEYCLOAK_ISSUER, audience: CLIENT_ID }); // 挂载用户信息到请求对象,供后续路由使用 req.user = decodedToken; next(); } catch (error) { return res.status(401).json({ error: '令牌无效或已过期' }); } }; // 受保护路由使用自定义中间件 app.get('/api/protected/data', validateKeycloakToken, (req, res) => { res.json({ data: '敏感数据', user: req.user }); });
常见遗漏点排查
- 未将后端客户端的访问类型设置为
bearer-only,导致校验逻辑异常 - 公钥配置时漏加
-----BEGIN PUBLIC KEY-----和-----END PUBLIC KEY-----包裹,导致签名校验失败 - 未处理令牌过期场景,需要返回401状态码触发前端重新申请令牌
- 校验逻辑漏校验issuer、audience字段,存在安全风险
内容的提问来源于stack exchange,提问作者Noman Tufail
相关产品推荐
相关产品推荐

