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.
so, I have tried to change the stream, but I have following issues:
The streams are empty, i.e. aResponseStream.Size = 0 and aRequestStream.Size = 0
What should they contain!?
I have tried to write on this way:
> procedure TMyROIndyHTTPServer.OnCustomResponseEvent(const aTransport: IROHTTPTransport; const aRequestStream,
> aResponseStream: TStream; const aResponse: IROHTTPResponse; var aHandled: Boolean);
> var
> lMessage: IROMessage;
> op: TROResponseOptions;
> s: AnsiString;
> begin
> // * extracting data if POST method was used
> SetLength(s, aRequestStream.Size);
> aResponseStream.Position := 0;
> aRequestStream.Read(Pointer(s)^, Length(s));
> // modify data in some way
> s := 'Status: 401 '+HTTP_401_status+s; // <---- I DON'T THINK THIS IS CORECCT. COULD YOU HELP ME HERE WITH THE CODE?
> // write updated data back to stream
> aRequestStream.Size := 0;
> aRequestStream.Write(Pointer(s)^, Length(s));
> // lMessage:= (FJSONMessage as IROMessageCloneable).Clone; // <--- WHAT KIND OF MESSAGE SHOULD I PROVIDE HERE?! I am working in my server with BIN, JSON and XML. How do I find out which message is triggered by client?!
> // MainProcessMessage(lMessage,atransport,aRequestStream,aResponseStream,op);
Your code works almost perfect! The problem is that my custom exception from a Service-RODataModule is catched and handled somewhere in MainProcessMessage(…). So, on E: MyError do begin can’t be reached, it goes directly to aHandled := True;