Page 1 of 1
Datasnap + ODAC. Passing DB credentials?
Posted: Fri 10 Apr 2015 20:44
by pacste
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?
Re: Datasnap + ODAC. Passing DB credentials?
Posted: Tue 14 Apr 2015 10:12
by AlexP
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 .
Re: Datasnap + ODAC. Passing DB credentials?
Posted: Thu 16 Apr 2015 18:11
by pacste
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
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
From the devart blog post you linked me:
Enter 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;
I can't figure out how to make it work, since the Server does not seem able to access ServerMethods components
Re: Datasnap + ODAC. Passing DB credentials?
Posted: Fri 17 Apr 2015 08:32
by AlexP
ServerMethods is a global variable in the ServerMethodsUnit1.cpp module (that you should assign by yourself)
Code: Select all
#include "ServerMethodsUnit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TServerMethods1 *ServerMethods1; //Add
//--------------------------------------------------------------------------
You should also add automatic creation of this object in the file project:
Code: Select all
Application->CreateForm(__classid(TServerContainer1), &ServerContainer1);
Application->CreateForm(__classid(TServerMethods1), &ServerMethods1); //Add
Re: Datasnap + ODAC. Passing DB credentials?
Posted: Tue 05 May 2015 18:36
by pacste
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.
Re: Datasnap + ODAC. Passing DB credentials?
Posted: Tue 05 May 2015 20:47
by pacste
I ported the code in Pascal and I think I have found a solution:
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;
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?
Re: Datasnap + ODAC. Passing DB credentials?
Posted: Wed 06 May 2015 07:36
by AlexP
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.