Skip to content

会话上下文

会话上下文是数据墙DBW 与 SQL Server 之间的声明传递通道。启用后,引擎将每次请求中 JWT 令牌的声明写入 SQL Server 的 SESSION_CONTEXT,使数据库内部的存储过程、视图和安全策略能够感知当前用户的身份信息。

IMPORTANT

会话上下文仅适用于 SQL Server(2016 及以上版本)。PostgreSQL 和 MySQL 不支持此功能。

什么是会话上下文

SQL Server 的 SESSION_CONTEXT 是一个会话级别的键值存储。每个数据库连接有自己的独立上下文空间。在连接持续期间,通过 sp_set_session_context 写入的键值对可以被该连接内的所有查询读取。

数据墙DBW 利用这个机制,在每次执行查询前将 JWT 声明写入会话上下文,从而让数据库内部能读取到调用用户的身份信息。

启用会话上下文

json
{
  "data-source": {
    "database-type": "mssql",
    "options": {
      "set-session-context": true
    }
  }
}

CLI 初始化时直接启用:

bash
dab init \
  --database-type "mssql" \
  --connection-string "<connection-string>" \
  --set-session-context true

默认值为 false。启用后引擎行为发生变化。

声明到会话上下文的映射

引擎将 JWT 令牌中的声明按以下规则写入 SESSION_CONTEXT

JWT 声明SESSION_CONTEXT 键示例值
subsubffffffff-eeee-dddd...
userIduserIduser_12345
rolesroleseditor
emailemailuser@example.com
namename张三
任意自定义声明声明原名声明原值

引擎会将 JWT 令牌中的所有声明写入会话上下文。声明名直接作为 SESSION_CONTEXT 的键。

引擎执行的 SQL

启用会话上下文后,引擎在每次查询前执行:

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 查询中

sql
-- 读取当前用户的角色
SELECT SESSION_CONTEXT(N'roles') AS current_role;

-- 读取当前用户的 ID
SELECT SESSION_CONTEXT(N'userId') AS current_user_id;

在安全策略中

sql
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 列进行比较。

在存储过程中

sql
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

存储过程读取会话上下文来实现用户级数据隔离。

在视图中

sql
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 ServerSQL Server、PostgreSQL、MySQL

选择建议:

  • 使用数据库策略作为默认方案——配置简单、对缓存友好、跨数据库一致。
  • 使用会话上下文 + 原生 RLS 当你有更高的安全要求(需要数据库层面的强制过滤)、已有成熟的 SQL Server 安全策略体系、或需要在存储过程中根据用户身份执行复杂逻辑。

手动测试会话上下文

在 SQL 客户端中模拟数据墙DBW 的行为:

sql
-- 设置会话上下文
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 ServerPostgreSQL 和 MySQL 不支持会话上下文
缓存被禁用启用后性能可能下降,需评估查询压力和索引优化
声明键名JWT 声明名直接映射为 SESSION_CONTEXT 键,注意大小写
连接复用连接池中的连接在每次请求前都会重新设置上下文值,不会残留上个请求的值
性能每次请求额外执行 sp_set_session_context 调用,开销很小(微秒级)

下一步

数据墙DBW 产品文档与开发指南。