共计 2796 个字符,预计需要花费 7 分钟才能阅读完成。
一、为什么需要 Token 认证?
在三维地理信息服务中,Cesium 作为前端可视化框架常需要对接敏感数据服务。Token 认证能有效解决两个核心问题:

- 身份验证:确保请求方是经过授权的合法用户
- 权限控制:限制不同用户对地图瓦片 / 地形数据的访问范围
传统 API Key 方式存在泄露风险,而 Token 具有时效性且可携带权限信息,更适合生产环境。
二、认证方案选型对比
| 方案类型 | 适用场景 | Cesium 适配性 |
|---|---|---|
| JWT | 需要自包含权限信息的场景 | 中等(需处理大 Token) |
| OAuth2.0 | 企业级统一认证 | 较差(流程复杂) |
| 自定义 Token | 简单快速的轻量级方案 | 优秀(灵活可控) |
对于多数 Cesium 项目,推荐采用 签名型自定义 Token,其优势在于:
- 可自主控制 Token 生命周期
- 避免 JWT 的膨胀问题
- 实现成本低
三、服务端实现(Node.js 示例)
1. Token 生成模块
const crypto = require('crypto');
// 配置参数
const TOKEN_SECRET = 'your_32byte_secret';
const TOKEN_TTL = 3600; // 1 小时有效
function generateToken(userId, accessScopes) {const timestamp = Math.floor(Date.now() / 1000);
const expireAt = timestamp + TOKEN_TTL;
// 构造签名数据
const payload = `${userId}|${expireAt}|${accessScopes.join(',')}`;
// 使用 HMAC-SHA256 生成签名
const hmac = crypto.createHmac('sha256', TOKEN_SECRET);
hmac.update(payload);
const signature = hmac.digest('hex');
// 返回 Base64 编码的 Token
return Buffer.from(`${payload}|${signature}`).toString('base64');
}
2. Token 验证中间件
function verifyTokenMiddleware(req, res, next) {
try {const token = req.headers['x-cesium-token'];
if (!token) throw new Error('Missing token');
// 解码 Base64
const decoded = Buffer.from(token, 'base64').toString('utf8');
const [payload, signature] = decoded.split('|').reverse();
// 验证签名
const hmac = crypto.createHmac('sha256', TOKEN_SECRET);
hmac.update(payload);
const expectedSig = hmac.digest('hex');
if (signature !== expectedSig) {throw new Error('Invalid signature');
}
// 解析 payload
const [userId, expireAt, scopes] = payload.split('|');
if (Date.now() > parseInt(expireAt) * 1000) {throw new Error('Token expired');
}
// 将用户信息附加到请求对象
req.user = {userId, scopes: scopes.split(',') };
next();} catch (err) {res.status(401).json({error: err.message});
}
}
四、前端集成方案
1. Cesium 资源加载配置
const viewer = new Cesium.Viewer('cesiumContainer', {
imageryProvider: new Cesium.IonResource.fromAssetId(YOUR_ASSET_ID, {
headers: {'X-Cesium-Token': getCurrentToken() // 从缓存或接口获取
}
}),
terrainProvider: new Cesium.CesiumTerrainProvider({
url: 'https://your-terrain-service.com',
headers: {'X-Cesium-Token': getCurrentToken()
}
})
});
2. Token 过期自动刷新
function setupTokenRefresh() {
// 检查剩余有效期
function checkTokenExpiry() {const token = getCurrentToken();
const {expireAt} = parseToken(token); // 实现解析逻辑
// 提前 5 分钟刷新
if (expireAt - Date.now() < 300000) {refreshToken().then(newToken => {updateAllProviders(newToken);
});
}
}
// 每小时检查一次
setInterval(checkTokenExpiry, 3600000);
}
五、安全与性能优化
1. 防重放攻击措施
- 在 Token payload 中添加随机数(nonce)
- 服务端维护短期 nonce 缓存
- 示例修改:
const nonce = crypto.randomBytes(8).toString('hex'); const payload = `${nonce}|${userId}|${expireAt}|${scopes}`;
2. 高并发优化
- 使用 Redis 缓存验证结果(设置合理 TTL)
- 采用 ECDSA 代替 HMAC 减少 CPU 消耗
- 负载均衡时确保时钟同步
六、生产环境避坑指南
-
CORS 配置:确保服务端返回正确的头信息
Access-Control-Allow-Headers: x-cesium-token Access-Control-Expose-Headers: x-token-renewal -
Token 泄露应对:
- 立即轮换 TOKEN_SECRET
- 在服务端维护吊销列表
-
缩短 Token 有效期
-
常见错误:
- 未处理 Token 刷新时的并发请求
- 忽略服务端时钟漂移
- 前端未处理 401 错误
七、延伸思考
如何实现动态权限控制?考虑以下方向:
- 在 Token 中嵌入细粒度权限声明(如区域边界)
- 服务端实时查询权限数据库
- 使用 OPA(Open Policy Agent)进行策略决策
- 双 Token 方案(访问 Token + 刷新 Token)
通过本文方案,您已掌握 Cesium 服务的安全接入核心方法。建议在实际项目中根据具体需求调整 Token 的生成和验证逻辑,并始终遵循最小权限原则。
正文完
发表至: 未分类
近两天内
