In moving my REST server to XData I have many service contracts but only one that requires Basic Authentication, my Login logic. The client is sending the encoded information in the header, but I don't understand what I have to do in XData to get those parameters. I have included the BASIC Authentication middleware, but don't know where the Username and Password are.
Sparkle Basic Auth Middleware will expect you to pass a TAuthenticateBasicProc as parameter for it's Create constructor. The middleware will give you user-id and password and you are supposed to give it back an IUserIdentity instance --or-- nil if not autorized.
You may also have a look at BasicAuth demo in XData install folder.
On Sparkle Basic Auth, there is also an OnAuthenticate event as another way to go.
I am not using Sparkle as a server, but rather I am using XDataServer. I only use the Sparkle Dispatcher
Yes. I got it. Basic Auth Middleware is from Sparkle. Anyway, for a XData RAD (component) aproach have a look at XData BasicAuth Demo. It shows how to use TSparkleBasicAuthMiddleware component Authenticate event handler :)
Here is what I did. In the OnAuthenticate event for XData Server:
procedure TServerContainer.XDataServerBasicauthAuthenticate(Sender: TObject;
const UserName, Password: string; var User: IUserIdentity);
if UserName <> '' then
User := TUserIdentity.Create;
Then in my service contract I access the information via:
sUserName := TXDataOperationContext.Current.Request.User.Claims.Find('username').AsString;
sPassword := TXDataOperationContext.Current.Request.User.Claims.Find('password').AsString;
Is this OK? Is there any significant overhead in having the Basic Auth Middleware active for all the other service contracts that don't send a username or password?
Your code is ok and should work. But if you only have basic authentication in a single method, and since Basic Authentication is rather really simple, maybe it would be easier that in your
Login method you just retrieve the basic authentication yourself, instead of using the middleware.
You can even copy/paste the code from
TBasicAuthMiddleware.ProcessRequest and adapt to your needs.
Auth := Context.Request.Headers.Get('authorization'); if (Auth <> '') and SameText('Basic ', Copy(Auth, 1, 6)) then begin Auth := TEncoding.UTF8.GetString(TSparkleUtils.DecodeBase64(Copy(Auth, 7, MaxInt))); P := Pos(':', Auth); if P > 0 then begin UserName := Copy(Auth, 1, P - 1); Password := Copy(Auth, P + 1, MaxInt); end; end;
Yes, your code is fine. I just would not set/keep the password on user claims. You should validate the username/password on XDataServerBasicauthAuthenticate and create TUserIdentity only if user is authorized.
Your services (probably) will not need to have any knowledge of the user password.
If you are setting the password in user clains to be able to validate the user on a service basis (each service may or may not do it's own validation) than Wagner's aproach it's probably best for you.