RemoteDB middleware Basic Authentication

Good afternoon,

where i need to declare the middleware Basic Authentication.

In your example, server side i have



procedure StartServer;

begin

if Assigned(SparkleServer) then

     Exit;



SparkleServer := THttpSysServer.Create;



Module := TRemoteDBModule.Create(

    'http://+:2001/tms/remotedb',     // original is 2001

    TFireDacFirebirdConnection.CreateFactory

);



Module.UserName:='UserName';

Module.Password:='UserPassword';



// Uncomment line below to enable CORS in the server

//Module.AddMiddleware(TCorsMiddleware.Create);



// Uncomment line below to allow compressed responses from server

//Module.AddMiddleware(TCompressMiddleware.Create);



SparkleServer.AddModule(Module);



SparkleServer.Start;

end;



This procedure is fired at mainform onshow event, so the server start.

I need to "customize" the login and this is possible via middleware Basic Authentication, but i do not understand where i need to declare it.

In you online doc i found



Module.AddMiddleware(TBasicAuthMiddleware.Create(

    procedure(const UserName, Password: string; var User: IUserIdentity)

    begin

      // Implement custom logic to authenticate user based on UserName and Password

      // For example, go to the database, check credentials and then create an user

      // identity with all permissions (claims) for this user

      User := TUserIdentity.Create;

      User.Claims.AddOrSet('roles').AsString := SomeUserPermission;

      User.Claims.AddOrSet('sub').AsString := UserName;

    end,

    'My Server Realm'

));



Do you have any example on how to use it ?



My need is when the client try to connect to the server, i check the credentials.



Thank's for all



Daniele

Hello Daniele,

You can add that code just before the call to AddModule. Also be sure to set Module.UserName and Module.Password to empty strings, so it doesn't enforce the default basic authentication.

Good morning Wagner,

excuse me ... but i have some problem with user autentication.

On server side i have a very simple server that is connected to a firebird db.

On client side i have a RemoteDb with XDataSet that send only one sql request.

What i need, and i'm not able to perform (it's my fault), is an user autentication.

when i click on connect button to the client the program runs



RDB1.ServerUri:=ServerUri;

RDB1.UserName:='pippo'

RDB1.Password:='pluto'

try

    RDB1.Connected:=True;

except on E: Exception do

     Begin

        // Some text here

     End;

end;



This user does not exist into userdb, server side.

Now, if the startserver procedure is



procedure StartServer;

var

Module : TRemoteDBModule;

aes    : TAESEncryption;

CrName : string;

CrPwd : string;

begin

if Assigned(SparkleServer) then

     Exit;



SparkleServer := THttpSysServer.Create;



Module := TRemoteDBModule.Create(

    'http://+:2001/tms/remotedb',

    TFireDacFirebirdConnection.CreateFactory

);

Module.AddMiddleware(TBasicAuthMiddleware.Create(

    procedure(const UserName, Password: string; var User: IUserIdentity)

    begin

       // Implement custom logic to authenticate user based on UserName and Password

      // For example, go to the database, check credentials and then create an user

      // identity with all permissions (claims) for this user

      User := TUserIdentity.Create;

      User.Claims.AddOrSet('UserName').AsString :=UserName;

      User.Claims.AddOrSet('UserPassword').AsString :=UserPassord;

    end,

    'My Server Realm'

));



Module.UserName:='';

Module.Password:='';



// Uncomment line below to enable CORS in the server

//Module.AddMiddleware(TCorsMiddleware.Create);



// Uncomment line below to allow compressed responses from server

//Module.AddMiddleware(TCompressMiddleware.Create);



SparkleServer.AddModule(Module);



SparkleServer.Start;

end;



How can i send back the string "User not found" ?

Also In documentation i found "Authorizing Requests" with procedure TProtectedHelloModule.ProcessRequest(const C: THttpServerContext);

but i did not understand how use it.

Now even if the username and/or userpassword are wrong RDB1.Connected always return true and the db is connected.



Excuse me for this "trivial" matter ...



Thank's for your patience

Regards

Daniele

Here is more or less what you have to do:




  Module.AddMiddleware(TBasicAuthMiddleware.Create(
    procedure(const UserName, Password: string; var User: IUserIdentity)
    begin
      if GoToDatabaseAndCheckIfUserExists(UserName, Password) then
      begin
        User := TUserIdentity.Create;
        User.Claims.AddOrSet('UserName').AsString :=UserName;
      end
      else
        User := nil;
    end,
    'My Server Realm'
  ));


  Module.AddMiddleware(TAnonymousMiddleware.Create(
    procedure(Context: THttpServerContext; Next: THttpServerProc)
    begin
      if Context.Request.User = nil then
      begin
        // no user authenticated, return error 401
        Context.Response.StatusCode := 401;
        Context.Response.ContentType := 'text/plain';
        Context.Response.Close(TEncoding.UTF8.GetBytes('User not authenticated'));
      end
      else
        Next(Context);
    end
  ));


The only part you need to implement yourself is the
GoToDatabaseAndCheckIfUserExists

, that's up to your business logic to check if the user is valid or not based on your criteria. I hope it helps.

Good morning Wagner,

yesterday evening i tried your suggested code .... and all works very good.

Studing your code i miss a lot of it (i.e. the second Module.AddMiddleware), now is a little clear and i can go ahead with the project.

Thank you, again, for your help and patience.



Regards

Daniele