Datasnap + ODAC. Passing DB credentials?
Datasnap + ODAC. Passing DB credentials?
I am trying to port an existing 2-tier project to a 3-tier technology, and Datasnap looks promising.
Now, the client must not have direct access to the Oracle DB (that is why I am looking for a 3-tier technology), but may have different DB credentials, so the Datasnap Server does not "know" the user and password for the TOraSession in advance.
Here is what I accomplished so far with my experiments:
Client Side
-DB Components...
-TOraDataSource
-TClientDataSet (Provider:OraProvider RemoteServer:DSProviderConnection)
-TSQLConnection (Driver: Datasnap)
-TDSProviderConnection (linked with SQLConnection and the remote Datasnap Server)
Server Side
-----Server Container Unit----
-TDSServer
-TDSServerClass
-----Server Methods Unit-------
-TOraProvider
-TOraQuery
-TOraSession
If I set the TOraSession by design the demo works, but I can't find a way to set the DB credentials from the client. TSQLConnection has a ServerConnection/Username/Password properties but they seem to work only with dbExpress.
Maybe some kind of RPC protocol?
Now, the client must not have direct access to the Oracle DB (that is why I am looking for a 3-tier technology), but may have different DB credentials, so the Datasnap Server does not "know" the user and password for the TOraSession in advance.
Here is what I accomplished so far with my experiments:
Client Side
-DB Components...
-TOraDataSource
-TClientDataSet (Provider:OraProvider RemoteServer:DSProviderConnection)
-TSQLConnection (Driver: Datasnap)
-TDSProviderConnection (linked with SQLConnection and the remote Datasnap Server)
Server Side
-----Server Container Unit----
-TDSServer
-TDSServerClass
-----Server Methods Unit-------
-TOraProvider
-TOraQuery
-TOraSession
If I set the TOraSession by design the demo works, but I can't find a way to set the DB credentials from the client. TSQLConnection has a ServerConnection/Username/Password properties but they seem to work only with dbExpress.
Maybe some kind of RPC protocol?
Re: Datasnap + ODAC. Passing DB credentials?
Hello,
For user authentication, you can use the TDSAuthenticationManager.OnUserAuthenticate event.
P.S. See an example of DataSnap application with our components in DAC Team's blog: http://blog.devart.com/using-dac-produc ... pment.html .
For user authentication, you can use the TDSAuthenticationManager.OnUserAuthenticate event.
P.S. See an example of DataSnap application with our components in DAC Team's blog: http://blog.devart.com/using-dac-produc ... pment.html .
Re: Datasnap + ODAC. Passing DB credentials?
Hi AlexP, thank you for the useful link.
I tried to use the OnUserAuthenticate event, but I couldn't find a way to access the ServerMethods unit from there.
I think I have the same issue as
http://stackoverflow.com/questions/2864 ... -server-me
TDSAuthenticationManager is in the Server
OraSession is in ServerMethods
How do I make the two units communicate?
This code does not link
From the devart blog post you linked me:
I tried to use the OnUserAuthenticate event, but I couldn't find a way to access the ServerMethods unit from there.
I think I have the same issue as
http://stackoverflow.com/questions/2864 ... -server-me
TDSAuthenticationManager is in the Server
OraSession is in ServerMethods
How do I make the two units communicate?
This code does not link
Code: Select all
void __fastcall TServerContainer1::DSAuthenticationManager1UserAuthenticate(TObject *Sender,
const UnicodeString Protocol, const UnicodeString Context, const UnicodeString User,
const UnicodeString Password, bool &valid, TStrings *UserRoles)
{
ServerMethods1->OraSession1->Username=User;
ServerMethods1->OraSession1->Password=Password;
valid = true;
}
Code: Select all
[ilink32 Error] Error: Unresolved external '_ServerMethods1' referenced from C:\PROJECTS\TESTDATASNAP\WIN32\DEBUG\SERVERCONTAINERUNIT1.OBJ
I can't figure out how to make it work, since the Server does not seem able to access ServerMethods componentsEnter the following code into the OnUserAuthenticate event:
ServerMethods.usp_check_user.ParamByName('a_username').AsString := User;
ServerMethods.usp_check_user.ParamByName('a_passwd').AsString := Password;
ServerMethods.usp_check_user.Execute;
valid := ServerMethods.usp_check_user.ParamByName('result').AsBoolean;
Re: Datasnap + ODAC. Passing DB credentials?
ServerMethods is a global variable in the ServerMethodsUnit1.cpp module (that you should assign by yourself)
You should also add automatic creation of this object in the file project:
Code: Select all
#include "ServerMethodsUnit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TServerMethods1 *ServerMethods1; //Add
//--------------------------------------------------------------------------
Code: Select all
Application->CreateForm(__classid(TServerContainer1), &ServerContainer1);
Application->CreateForm(__classid(TServerMethods1), &ServerMethods1); //Add
Re: Datasnap + ODAC. Passing DB credentials?
Hi Alex,
I did what you suggested, but it doesn't work. I was able to create a global ServerMethods variable, but it is useless because each session creates its own ServerMethods instance anyway. I can send you my test project if you want, it's tiny.
I did what you suggested, but it doesn't work. I was able to create a global ServerMethods variable, but it is useless because each session creates its own ServerMethods instance anyway. I can send you my test project if you want, it's tiny.
Re: Datasnap + ODAC. Passing DB credentials?
I ported the code in Pascal and I think I have found a solution:
ServerContainerUnit
Let me know if it can be improved. I am worried about the eventual race conditions on the two vars: what happens when two clients try to login at the same time?
ServerContainerUnit
Code: Select all
implementation
{$R *.dfm}
uses Winapi.Windows, ServerMethodsUnit1, Datasnap.DSProviderDataModuleAdapter,Datasnap.DataBkr;
threadvar
thread_username:string;
thread_password:string;
procedure TServerContainer1.DSServerClass1GetClass(
DSServerClass: TDSServerClass; var PersistentClass: TPersistentClass);
begin
PersistentClass := ServerMethodsUnit1.TServerMethods1;
end;
procedure TServerContainer1.DSServerClass1Prepare(DSPrepareEventObject: TDSPrepareEventObject);
var
a:TDSProviderDataModuleAdapter;
b:TServerMethods1;
begin
a:=(DSPrepareEventObject.MethodInstance as TDSProviderDataModuleAdapter);
b:=(a.ProviderDataModule as TServerMethods1);
b.OraSession1.UserName := thread_username;
b.OraSession1.Password := thread_password;
end;
procedure TServerContainer1.DSAuthenticationManager1UserAuthenticate(
Sender: TObject; const Protocol, Context, User, Password: string;
var valid: Boolean; UserRoles: TStrings);
begin
thread_username:=User;
thread_password:=Password;
valid := True;
end;
Re: Datasnap + ODAC. Passing DB credentials?
To implement such behavior, you should include the Pooling property of OraSesssion. In this case, a separate connection will be created for each user and placed to the connection pool. Otherwise, there will be only one connection, and users will always change.