Of course I can pass a username and password to the method, but then I should pass these parameters to each service method which I have? And I dont’t want to do this. I would like to login only once and call all methods of a service.
Oooohh! So stupid! Sorry for that stupid question! I can just use the http header variables, but the right way would be to use the basic http authentication.
have you set RequireHTTPAuthentication to true?
server should return 401 code if authorization is failed/isn’t found.
your client-side should catch this code and provide correct info.
you can create simple delphi client and review how server-side works.
you can use Session feature. it allows to “protect” some services.
“Protected” services should have RequiresSession = True and assigned SessionManager.
Note: LoginService should have RequiresSession = False, otherwise clients can’t access to it.
Ok, I can use session, but I can also pass user/password in the http headers and read it in RORemoteDataModuleGetDispatchInfo of a Service-RODataModule. Right?
So, I can check the http headers and if I don’t find user/password I want to send back the 401 HTTP status code. Is it possible to do? Here is an example
procedure TMyService.RORemoteDataModuleGetDispatchInfo(const aTransport: IROTransport; const aMessage: IROMessage);
var
TCPInfo:IROTCPtransport;
HTTPInfo:IROHTTPTransport;
Authorization: string;
begin
if Supports(aTransport, IROHTTPTransport, HTTPInfo) then
begin
WWWAuthenticate := HTTPInfo.Headers['WWW-Authenticate'];
Authorization := HTTPInfo.Headers['Authorization'].Substring(Length('Basic')+Pos('Basic ', HTTPInfo.Headers['Authorization']));
Authorization_Decoded := Soap.EncdDecd.DecodeString(Authorization);
if Authorization_Decoded <> 'I am OK' then
begin
// how to return here 401 status code?!
end;
end;
end;
try to cast aTransport to IROHTTPRequest as you did for IROHTTPTransport.
also this method should fall with exception otherwise execution will be continued.
tested! It works! Thanks! Buuuuut, my question remains
If I raise an exception the client gets the http status code 200 OK but with an error. And I would like to return the code 401. How can I do this?
if Supports(aTransport, IROHTTPRequest, HTTPRequestInfo) then
begin
UsesAuthentication := HTTPRequestInfo.UsesAuthentication;
AuthUsername := HTTPRequestInfo.AuthUsername;
AuthPassword := HTTPRequestInfo.AuthPassword;
if AuthUsername <> 'I am OK' then
begin
HTTPRequestInfo.Headers['Status'] := 'Status: 401 Unauthorized';
raise Exception.Create('Unauthorized');
end;
end;
The result is with the Status: 200 OK
{
“version”: “1.1”,
“error”: {
“name”: “JsonRPCError”,
“code”: “1”,
“message”: “Unauthorized”
}
}
you can’t do this with std implementation, but you can reach this with HTTPServer.OnCustomResponseEvent.
just raise custom error and catch it inside this event and pass into aResponse.