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

Delphi(FireDAC)桌面应用登录后多用户会话差异化实现咨询

解决Delphi + FireDAC + MSSQL桌面应用多用户会话隔离问题

嘿,我来帮你搞定这个问题——你现在的核心痛点就是没有为每个登录用户建立独立的会话上下文,导致所有用户共享了同一套数据库连接、状态判断逻辑,自然看到的数据和能用的功能都一模一样。下面是针对桌面应用场景的具体落地方案,完全不需要分布式那套复杂架构:

1. 给每个用户分配专属的FireDAC连接

别再用全局共享的FDConnection了!这是串用数据的根源。你可以封装一个用户会话类,把用户信息和专属数据库连接绑定在一起:

type
  TUserSession = class
  public
    UserID: Integer;
    UserName: string;
    Permissions: TStringList; // 存用户的功能权限,比如['查看订单', '编辑客户']
    DBConn: TFDConnection;
    constructor Create;
    destructor Destroy; override;
  end;

constructor TUserSession.Create;
begin
  inherited;
  DBConn := TFDConnection.Create(nil);
  // 配置MSSQL连接参数:服务器、数据库名这些根据你的实际情况填
  DBConn.DriverName := 'MSSQL';
  DBConn.Params.Values['Server'] := '你的SQL服务器地址';
  DBConn.Params.Values['Database'] := '你的数据库名';
  // 如果是业务层区分用户(共用一个数据库登录账号),这里就用通用账号密码;如果每个用户有独立SQL账号,就用用户输入的账号密码配置
  DBConn.Connected := True;
end;

destructor TUserSession.Destroy;
begin
  DBConn.Free;
  inherited;
end;

登录成功后,实例化这个TUserSession,把它存在主窗体的属性里(或者一个全局变量,但如果支持多窗口登录,最好绑定到对应窗口),后续所有数据库操作都用这个专属的DBConn。

2. 数据库层面实现数据隔离

光有独立连接还不够,得确保每个用户只能看到自己的数据,两种常用方式:

方式一:业务SQL里加用户ID过滤

这是最直接的方式,所有查询都带上当前用户的ID作为条件:

// 假设当前会话存在MainForm.UserSession里
FDQuery.SQL.Text := 'SELECT * FROM 订单表 WHERE 创建人ID = :CurrentUserID';
FDQuery.ParamByName('CurrentUserID').AsInteger := MainForm.UserSession.UserID;
FDQuery.Open;

方式二:用MSSQL行级安全(RLS)自动过滤

如果不想每个SQL都写过滤条件,可以在数据库端配置RLS,让数据库自动帮你过滤数据:
首先在SQL Server里创建会话上下文函数和安全策略:

-- 创建获取当前用户ID的函数
CREATE FUNCTION dbo.GetCurrentLoginUserID()
RETURNS INT
WITH SCHEMABINDING
AS
BEGIN
  RETURN CAST(SESSION_CONTEXT(N'LoginUserID') AS INT);
END;

-- 给订单表添加行级安全策略
CREATE SECURITY POLICY OrderDataFilterPolicy
ADD FILTER PREDICATE dbo.GetCurrentLoginUserID() = 创建人ID
ON dbo.订单表
WITH (STATE = ON);

然后在Delphi登录成功后,通过专属连接把当前用户ID写入数据库会话上下文:

MainForm.UserSession.DBConn.ExecSQL('EXEC sp_set_session_context N''LoginUserID'', :UserID', [MainForm.UserSession.UserID]);

这样之后,所有针对订单表的查询都会自动过滤,不用在业务代码里加条件,非常省心。

3. 功能权限的隔离控制

要让不同用户用不同功能,得做两步:

  • 登录时从数据库加载用户的权限列表(比如从用户权限表查询该用户拥有的权限),存入TUserSession.Permissions
  • 在界面和业务逻辑层做权限校验:
// 比如判断用户是否有编辑客户的权限
if MainForm.UserSession.Permissions.IndexOf('编辑客户') = -1 then
begin
  btnEditCustomer.Enabled := False;
  ShowMessage('抱歉,你没有编辑客户的权限');
end;

注意:别只在界面层做控制!业务逻辑层也要加校验,防止用户通过直接调用方法等方式绕过界面限制。

4. 会话管理的关键注意点

  • 用户注销时,一定要销毁对应的TUserSession实例,关闭专属的FDConnection,释放资源,避免内存泄漏和连接占用
  • 如果你的应用支持同时登录多个用户(比如开多个窗口对应不同账号),要确保每个窗口绑定自己的TUserSession,别共用全局实例,可以把会话存在窗口的Tag属性或者自定义属性里
  • 如果有后台线程处理数据库操作,要确保线程使用的是当前用户的专属连接,别用全局连接

避坑提醒

  • 绝对不要共用全局FDConnection:哪怕你登录后切换数据库用户,也可能因为连接池或会话上下文残留导致数据串用
  • 权限控制要多层校验:界面层、业务逻辑层、数据库层都要做,确保万无一失
  • 用RLS的话,要注意连接断开重连后,需要重新设置会话上下文,否则过滤会失效

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:13:35