XDATA - JWT - LOGIN

We are using XDATA for REST SERVER and trying user LoginService according demo. We have the token with success full but when user POSTMAN for other functions ("Example: Table Acesso") receive message "User not Authorized". Code Delphi Server:

unction TaccesoService.Getacceso_id(codigo: Integer): Tacceso;
var
User: IUserIdentity;

begin

User := TXDataOperationContext.Current.Request.User;
if User = nil then
raise EXDataHttpUnauthorized.Create('User not authenticated');
if not (User.Claims.Exists('admin') and User.Claims['admin'].AsBoolean) then
raise EXDataHttpForbidden.Create('Not enough privileges');

Query.SQL.Text := 'SELECT * FROM ACESSO WHERE CODIGO = :codigo';
Query.ParamByName('codigo').AsInteger := codigo;
Query.Open;
if Query.IsEmpty then Exit(nil);

Result := Tacceso.Create;
TXDataOperationContext.Current.Handler.ManagedObjects.Add(Result);
Result.codigo := Query.FieldByName('codigo').AsInteger;
Result.usuario := Query.FieldByName('usuario').AsString;
Result.senha := Query.FieldByName('senha').AsString;
end;

POSTMAN : http://192.168.1.19:2001/tms/firedacsql/acesso with HEADER: Authorization: "Bearer eyJhbGciOiJIUzI1NiJ9.eyJVc2VyIjoiYWRtaW4iLCJQYXNzd29yZCI6ImFkbWluIn0.bAOqLbGpIzor6ujxC18xd2sy9svwn8Ba4SlzI4RVwlY"

Thanks in advance

Your token is really strange, it includes UserName and Password properties which should not be there, especially Password.

Please make your project minimal and send the project and steps to reproduce the issue.

Dear Wagner. Thaks for your reply. Below the 3 units related with Login function

unit LoginService;

interface

uses
  XData.Service.Common;

type
  [ServiceContract]
  ILoginService = interface(IInvokable)
    ['{78F7B6F6-863F-4DCE-A4EA-95C16772600B}']
   function Login(const User, Password: string): string;
  end;

implementation

end.
unit LoginServiceImplementation;

interface

uses
  XData.Server.Module,
  XData.Service.Common,
  LoginService;

type
  [ServiceImplementation]
  TLoginService = class(TInterfacedObject, ILoginService)
  public
    function Login(const User, Password: string): string;
  end;

implementation

uses
  Bcl.JOSE.Core.Builder,
  Bcl.JOSE.Core.JWT,
  XData.Sys.Exceptions;

{ TLoginService }

 Const
 JWT_SECRET = 'super_secret_0123456789_0123456789';

function TLoginService.Login(const User, Password: string): string;
var
  JWT: TJWT;
  Scopes: string;
begin
   { check if UserName and Password are valid, retrieve User data from database,
   add relevant claims to JWT and return it. In this example, we will accept any
   user as long the password is the same }
  if User <> Password then
    raise EXDataHttpUnauthorized.Create('Invalid password');

  // Generate the token
  JWT := TJWT.Create(TJWTClaims);
  try
    JWT.Claims.SetClaimOfType<string>('username', User);
    JWT.Claims.Issuer := 'XData Server';
    Result := TJOSE.SHA256CompactToken(JWT_SECRET, JWT);
  finally
    JWT.Free;
  end;
end;

initialization
  RegisterServiceType(TLoginService);
end.
unit accesoServiceImplementation;

interface

uses
  XData.Server.Module,
  XData.Service.Common,
  Generics.Collections,
  Data.DB, FireDAC.Comp.Client, FireDAC.Stan.Param,
  DM,
  accesoService,
  Sparkle.Security, XData.Sys.Exceptions;

type
  [ServiceImplementation]
  TaccesoService = class(TInterfacedObject, IaccesoService)
   strict private
    DB: TDataModule1;
    function GetQuery: TFDQuery;
   public
    procedure AfterConstruction; override;
    procedure BeforeDestruction; override;
    property Query: TFDQuery read GetQuery;
   public
   function Getacceso_id(codigo: Integer): Tacceso;
   function Getacceso_list: TList<Tacceso>;
  end;

implementation

function TaccesoService.GetQuery: TFDQuery;
begin
  Result := DB.FDQuery2;
end;

procedure TaccesoService.AfterConstruction;
begin
  inherited;
  DB := TDataModule1.Create(nil);
end;

procedure TaccesoService.BeforeDestruction;
begin
  DB.Free;
  inherited;
end;


function TaccesoService.Getacceso_id(codigo: Integer): Tacceso;
var
  User: IUserIdentity;

  begin

  User := TXDataOperationContext.Current.Request.User;
  if User = nil then
    raise EXDataHttpUnauthorized.Create('User not authenticated');
  if not (User.Claims.Exists('admin') and User.Claims['admin'].AsBoolean) then
    raise EXDataHttpForbidden.Create('Not enough privileges');


  Query.SQL.Text := 'SELECT * FROM ACESSO WHERE CODIGO = :codigo';
  Query.ParamByName('codigo').AsInteger := codigo;
  Query.Open;
  if Query.IsEmpty then Exit(nil);

  Result := Tacceso.Create;
  TXDataOperationContext.Current.Handler.ManagedObjects.Add(Result);
  Result.codigo := Query.FieldByName('codigo').AsInteger;
  Result.usuario := Query.FieldByName('usuario').AsString;
  Result.senha := Query.FieldByName('senha').AsString;
end;


function TaccesoService.Getacceso_list: TList<Tacceso>;
var
  acceso: Tacceso;
   User: IUserIdentity;



begin


  User := TXDataOperationContext.Current.Request.User;
  if User = nil then
    raise EXDataHttpUnauthorized.Create('User not authenticated');
  if not (User.Claims.Exists('admin') and User.Claims['admin'].AsBoolean) then
    raise EXDataHttpForbidden.Create('Not enough privileges');

  Result := TList<Tacceso>.Create;
  TXDataOperationContext.Current.Handler.ManagedObjects.Add(Result);
  Query.SQL.Text := 'SELECT codigo, usuario, senha FROM ACESSO ORDER BY usuario';
  Query.Open;
  while not Query.Eof do
  begin
    acceso := Tacceso.Create;
    TXDataOperationContext.Current.Handler.ManagedObjects.Add(acceso);
    Result.Add(acceso);
    acceso.codigo := Query.FieldByName('codigo').AsInteger;
    acceso.usuario := Query.FieldByName('usuario').AsString;
    acceso.senha := Query.FieldByName('senha').AsString;
    Query.Next;
  end;
end;


initialization
  RegisterServiceType(TaccesoService);

end.

I'm not sure what I should do with this code. Your original claim is:

We have the token with success full but when user POSTMAN for other functions ("Example: Table Acesso") receive message "User not Authorized"

I don't even see "User not Authorized" message anywhere in this code.

Have you added the JWT middleware to your API to process the received JWT tokens?

Excuse me . The message is "User not authenticated"

unit accesoServiceImplementation;

interface

uses
  XData.Server.Module,
  XData.Service.Common,
  Generics.Collections,
  Data.DB, FireDAC.Comp.Client, FireDAC.Stan.Param,
  DM,
  accesoService;

type
  [ServiceImplementation]
  TaccesoService = class(TInterfacedObject, IaccesoService)
   strict private
    DB: TDataModule1;
    function GetQuery: TFDQuery;
   public
    procedure AfterConstruction; override;
    procedure BeforeDestruction; override;
    property Query: TFDQuery read GetQuery;
   public
   function Getacceso_id(codigo: Integer): Tacceso;
   function Getacceso_list: TList<Tacceso>;
  end;

implementation

uses
  Aurelius.Drivers.Interfaces, System.IOUtils,
  Bcl.Jose.Core.JWT,  Bcl.JOSE.Core.Builder,
   XData.Sys.Exceptions, Sparkle.Middleware.Jwt,  Sparkle.HttpSys.Server, LoginServiceImplementation;



function TaccesoService.GetQuery: TFDQuery;
begin
  Result := DB.FDQuery2;
end;

procedure TaccesoService.AfterConstruction;
begin
  inherited;
  DB := TDataModule1.Create(nil);
end;

procedure TaccesoService.BeforeDestruction;
begin
  DB.Free;
  inherited;
end;


function TaccesoService.Getacceso_id(codigo: Integer): Tacceso;
var
  User: IUserIdentity;

  begin


    User := TXDataOperationContext.Current.Request.User;
  if User = nil then
    raise EXDataHttpUnauthorized.Create('User not authenticated');
  if not (User.Claims.Exists('admin') and User.Claims['admin'].AsBoolean) then
    raise EXDataHttpForbidden.Create('Not enough privileges');


  Query.SQL.Text := 'SELECT * FROM ACESSO WHERE CODIGO = :codigo';
  Query.ParamByName('codigo').AsInteger := codigo;
  Query.Open;
  if Query.IsEmpty then Exit(nil);

  Result := Tacceso.Create;
  TXDataOperationContext.Current.Handler.ManagedObjects.Add(Result);
  Result.codigo := Query.FieldByName('codigo').AsInteger;
  Result.usuario := Query.FieldByName('usuario').AsString;
  Result.senha := Query.FieldByName('senha').AsString;
end;


function TaccesoService.Getacceso_list: TList<Tacceso>;
var
  acceso: Tacceso;
   User: IUserIdentity;



begin




  Result := TList<Tacceso>.Create;
  TXDataOperationContext.Current.Handler.ManagedObjects.Add(Result);
  Query.SQL.Text := 'SELECT codigo, usuario, senha FROM ACESSO ORDER BY usuario';
  Query.Open;
  while not Query.Eof do
  begin
    acceso := Tacceso.Create;
    TXDataOperationContext.Current.Handler.ManagedObjects.Add(acceso);
    Result.Add(acceso);
    acceso.codigo := Query.FieldByName('codigo').AsInteger;
    acceso.usuario := Query.FieldByName('usuario').AsString;
    acceso.senha := Query.FieldByName('senha').AsString;
    Query.Next;
  end;
end;


initialization
  RegisterServiceType(TaccesoService);

end.

What about this?

I thought it would be the form "unit accessServiceImplementation;" Does this work or am I wrong?

I'm not sure what you mean? Have you added JWT middleware, which is the responsible for processing the JWT and setting the Request.User object?

Thanks

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.