如何在Datasnap Server Methods单元中获取经过身份验证的用户名和密码?

时间:2015-02-21 16:44:04

标签: delphi authentication datasnap

使用正确的参数名称后,Datasnap身份验证非常简单(在Delphi Datasnap Server User Authentication中说明)。下一个问题是在使用FireDAC数据库连接时能够使用这些相同的凭据。答案似乎隐含在Most efficient way to pass SQL Login credentials to Delphi Datasnap servers?中,尽管"简单转发"并没有真正解释如何完成代码。此外,这些凭据应该作为用于登录Datasnap服务器的相同凭据进行身份验证。这样可以防止在数据库级别进行模拟。

到目前为止,我还没有找到任何方法从Server Methods单元中以编程方式获取当前的Datasnap用户凭据。例如,在BeforeConnect事件中。我正在使用的代码是使用Delphi XE7使用会话生命周期构建的独立服务器。

以下是连接到Datasnap服务器并请求数据时发生的事件的说明:

让我进一步解释一下:

通过使用一些ShowMessage指令,我可以在连接并发出数据请求时跟踪Datasnap的流程。在Test下运行服务器允许我显示事件附带的各种参数的内容。设置完成后,运行连接到服务器并请求数据的客户端将产生以下结果:

客户端登录按钮

  • 提供了凭证对话(这是我的代码,而不是我的代码 错误的TSQLConnection。)
  • 输入用户名和密码。
  • 放置在TSQLConnection.Params中的参数[DSAuthenticationPassword,DSAuthenticationUser]
  • 设置TSQLConnection.Connected:= True
  • 服务器事件OnUserAuthenticate

    此时,连接已建立,但没有别的 发生在服务器上。最重要的是,既不是ServerClass ServerMethodsClass也没有实例化。没有地方 我可以看到存储身份验证凭据。

客户端GetData按钮

  • 客户端连续打开两个客户端数据集。
  • 服务器DSServerClass1.Create。这显然意味着 ServerTransport将请求识别为有效并进入
    创建必要的资产来处理会话。
  • ServerMethodsUnit3.Create。埋藏在DSServerClass中的某个地方 有一个GetClass调用返回的名称 关联的ServerMethodsClass。命名类被实例化。以来 ServerMethodsClass最终来自TDataModule 也意味着物业流。
  • OnUserAuthorize(显然是第一个数据集)
  • OnUserAuthorize(显然是第二个数据集)

将数据返回给客户端(此时,数据库凭据被硬编码到TFDConnection ConnectionDefinition中,只是为了将其转换为    的工作。)

OnUserAuthorize使用nil值显示Sender参数;还提供了一个TDSAuthorizeEventObject,它不包含我能够用来查找ServerMethods实例的任何引用,最后还有一个名为Valid的参数,一个用于授权用户的布尔值。

请注意,TDSAuthorizeEventObject包含对TDSServerMethodUserEventObject的引用,该引用包含用户名以及角色,授权角色和拒绝角色。但是,那又怎样?这让我回到原来的问题:如何将此信息传达给ServerMethodsUnit中的代码?

2 个答案:

答案 0 :(得分:6)

过了一段时间,我在Bob Swart的白皮书中偶然发现了确切的方法。有几种方法可以让您在Datasnap会话期间保留信息。它们属于TDSSessionManager.GetThreadSession,分别是GetData,PutData,RemoveData,HasData,GetObject,PutObject,RemoveObject和HasObject。这些方法实际上管理了作为Session一部分的两个字典。例如,在UserAuthentication事件中,您可以按如下方式存储用户名:

TDSSessionManager.GetThreadSession.PutData('entrykey', UserName);

稍后,在数据库连接的OnBeforeConnect事件中,您可以检索这些值以便在连接中使用:

DBUserName := TDSessionManager.GetThreadSession.GetData('entrykey');

在实践中,我发现"对象"价值更高的形式,但任何一种形式都提供了一种强大的方式,可以在不诉诸外部媒体的情况下在会话期间保留您自己的数据。

答案 1 :(得分:0)

在关联的question中,TServerContainer1.DSAuthenticationManager1UserAuthenticate方法包含UserPassword个参数。您的服务器端代码可以从请求参数中检索凭据,验证它们,然后重新使用它们进行数据库身份验证。

procedure TServerContainer1.DSAuthenticationManager1UserAuthenticate(
  Sender: TObject; const Protocol, Context, User, Password: string;
  var valid: Boolean; UserRoles: TStrings);

if UserService.isUserValid(User, Password) then
begin
  // use User and Password ... 

end;