会话上下文
会话上下文是数据墙DBW 与 SQL Server 之间的声明传递通道。启用后,引擎将每次请求中 JWT 令牌的声明写入 SQL Server 的 SESSION_CONTEXT,使数据库内部的存储过程、视图和安全策略能够感知当前用户的身份信息。
IMPORTANT
会话上下文仅适用于 SQL Server(2016 及以上版本)。PostgreSQL 和 MySQL 不支持此功能。
什么是会话上下文
SQL Server 的 SESSION_CONTEXT 是一个会话级别的键值存储。每个数据库连接有自己的独立上下文空间。在连接持续期间,通过 sp_set_session_context 写入的键值对可以被该连接内的所有查询读取。
数据墙DBW 利用这个机制,在每次执行查询前将 JWT 声明写入会话上下文,从而让数据库内部能读取到调用用户的身份信息。
启用会话上下文
{
"data-source": {
"database-type": "mssql",
"options": {
"set-session-context": true
}
}
}CLI 初始化时直接启用:
dab init \
--database-type "mssql" \
--connection-string "<connection-string>" \
--set-session-context true默认值为 false。启用后引擎行为发生变化。
声明到会话上下文的映射
引擎将 JWT 令牌中的声明按以下规则写入 SESSION_CONTEXT:
| JWT 声明 | SESSION_CONTEXT 键 | 示例值 |
|---|---|---|
sub | sub | ffffffff-eeee-dddd... |
userId | userId | user_12345 |
roles | roles | editor |
email | email | user@example.com |
name | name | 张三 |
| 任意自定义声明 | 声明原名 | 声明原值 |
引擎会将 JWT 令牌中的所有声明写入会话上下文。声明名直接作为 SESSION_CONTEXT 的键。
引擎执行的 SQL
启用会话上下文后,引擎在每次查询前执行:
EXEC sp_set_session_context 'roles', 'editor', @read_only = 0;
EXEC sp_set_session_context 'userId', 'user_12345', @read_only = 0;
EXEC sp_set_session_context 'sub', 'ffffffff-eeee-dddd...', @read_only = 0;
-- 然后执行实际的查询
SELECT * FROM dbo.Orders;@read_only = 0 表示这些值在会话期间可以被后续的 sp_set_session_context 调用覆盖。
在数据库中读取会话上下文
在 SQL 查询中
-- 读取当前用户的角色
SELECT SESSION_CONTEXT(N'roles') AS current_role;
-- 读取当前用户的 ID
SELECT SESSION_CONTEXT(N'userId') AS current_user_id;在安全策略中
CREATE FUNCTION dbo.OrderPredicate(@ownerId VARCHAR(100))
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN SELECT 1 AS result
WHERE @ownerId = CAST(SESSION_CONTEXT(N'userId') AS VARCHAR(100));安全策略中的 SESSION_CONTEXT(N'userId') 动态获取当前请求用户的 ID,与表中的 ownerId 列进行比较。
在存储过程中
CREATE PROCEDURE dbo.GetMyOrders
AS
BEGIN
DECLARE @userId VARCHAR(100) = CAST(SESSION_CONTEXT(N'userId') AS VARCHAR(100));
SELECT * FROM dbo.Orders WHERE ownerId = @userId;
END存储过程读取会话上下文来实现用户级数据隔离。
在视图中
CREATE VIEW dbo.vw_MyOrders AS
SELECT *
FROM dbo.Orders
WHERE ownerId = CAST(SESSION_CONTEXT(N'userId') AS VARCHAR(100));同一视图在不同用户请求时返回不同结果——视图定义不变,但 SESSION_CONTEXT 因用户而异。
缓存影响
WARNING
启用 set-session-context 后,数据墙DBW 自动禁用该数据源的响应缓存。原因是:
- 缓存键中包含"请求路由 + 查询参数",但不包含"会话上下文值"。
- 两个不同用户的相同查询产生的数据库结果集不同(因为安全策略或存储过程的过滤逻辑依赖
SESSION_CONTEXT)。 - 如果不禁用缓存,用户 A 的查询结果可能被错误地返回给用户 B。
这意味着启用会话上下文后,每次查询都会命中数据库。如果需要缓存优势,考虑使用数据墙DBW 的数据库策略(@claims 引用)替代——数据墙DBW 在处理策略时会将用户身份纳入缓存键的计算,允许跨用户共享缓存的同时保持隔离。
会话上下文 vs 数据库策略
| 维度 | 会话上下文 + 原生 RLS | 数据库策略 |
|---|---|---|
| 过滤执行位置 | 数据库层 | 数据墙DBW 引擎层 |
| 配置复杂度 | 高(需要 SQL Server 安全策略) | 低(在 dab-config.json 中配置) |
| 绕过 DAB 时 | 过滤仍然生效 | 过滤不生效 |
| 对缓存的影响 | 自动禁用缓存 | 缓存正常可用 |
| 灵活性 | 可实现复杂的安全逻辑 | OData 表达式范围内 |
| 跨数据库 | 仅 SQL Server | SQL Server、PostgreSQL、MySQL |
选择建议:
- 使用数据库策略作为默认方案——配置简单、对缓存友好、跨数据库一致。
- 使用会话上下文 + 原生 RLS 当你有更高的安全要求(需要数据库层面的强制过滤)、已有成熟的 SQL Server 安全策略体系、或需要在存储过程中根据用户身份执行复杂逻辑。
手动测试会话上下文
在 SQL 客户端中模拟数据墙DBW 的行为:
-- 设置会话上下文
EXEC sp_set_session_context 'roles', 'editor';
EXEC sp_set_session_context 'userId', 'user_12345';
-- 验证当前值
SELECT
SESSION_CONTEXT(N'roles') AS role,
SESSION_CONTEXT(N'userId') AS user_id;
-- 查询受安全策略保护的表
SELECT * FROM dbo.Revenues;在开发阶段,这种方式可以快速验证安全策略逻辑是否正确,不需要反复启动数据墙DBW 并通过 HTTP 请求测试。
注意事项
| 注意事项 | 说明 |
|---|---|
| 仅 SQL Server | PostgreSQL 和 MySQL 不支持会话上下文 |
| 缓存被禁用 | 启用后性能可能下降,需评估查询压力和索引优化 |
| 声明键名 | JWT 声明名直接映射为 SESSION_CONTEXT 键,注意大小写 |
| 连接复用 | 连接池中的连接在每次请求前都会重新设置上下文值,不会残留上个请求的值 |
| 性能 | 每次请求额外执行 sp_set_session_context 调用,开销很小(微秒级) |
