Quantcast
Viewing all articles
Browse latest Browse all 3686

Authenticated/Authorized CRUDs

I'm learning to code with Delphi 12 and I'm trying to create a simple app for an agenda.

I have a mySQL database set up with 2 tables:

users
id
username
password
appointments
id
user_id (FK)
Company
Date
Time

I already coded a full-stack version of the app but now I'm trying to split the client and server by using TMS XData as framework for my server.

I have declared and mapped the User and Appointment entities and the automatically generated CRUDs work but I need to authorize the operation of reading and writing only the appointment entities bound to the logged user. I created a JWT Login Service that works and correctly returns the token but I'm not sure on how to modify the CRUDs to make use of that token to authorize the operations.

How should I proceed?

PS. I'm using FireDAC components to connect to the database.

By reading the DOCs I understood that I should be using both TMS Spark's Middleware to verify if the token is correct and possibly [EntityAuthorize(EntitySetPermissions*OPERATION*)] when declaring the object but I'm not sure if this is right and how to check for the right user_id.

This is what I tried to do but when testing using Postman, it always returns 404. My server is running on "http://localhost:2001/tms/xdata" so what in Postman the URL I'm using is "http://localhost:2001/tmx/xdata/CRUDService/GetAppointments" with method GET and with the Authorization key in the Headers with value "Bearer my-jwt".

unit CRUDServiceImplementation_u;interfaceuses  XData.Service.Common,  XData.Server.Module,  XData.Sys.Exceptions,  FireDAC.Comp.Client,  Data.DB,  AppointmentObj_u, LoginUser_u,  GlobalElements_u,  System.Generics.Collections,  CRUDService_u,  JOSE.Core.JWT,  JOSE.Core.JWS,  JOSE.Core.Builder,  Sparkle.Security;type  [ServiceImplementation]  TCRUDService = class(TInterfacedObject, ICRUDService)  private  function GetUserID: integer;  public [HttpGet] function GetAppointments: TList<TAppointment>; [HttpPost] procedure AddAppointment(const Appointment: TAppointment); [HttpPatch] procedure UpdateAppointment(const Appointment: TAppointment); [HttpDelete] procedure DeleteAppointment(const ID: Integer);  end;implementationuses  System.SysUtils;function TCRUDService.GetUserID: Integer;var  CurrentUserID: Integer;  User: IUserIdentity;  Query: TFDQuery;begin  User := TXDataOperationContext.Current.Request.User;  if User = nil then    raise EXDataHttpUnauthorized.Create('User not authenticated');  Query := TFDQuery.Create(nil);  try    Query.Connection := FDConnection1;    Query.SQL.Text := 'SELECT Id FROM users WHERE username = :username AND password = :password';    Query.ParamByName('username').AsString := User.Claims['username'].AsString;    Query.ParamByName('password').AsString := User.Claims['password'].AsString;    Query.Open;    if not Query.IsEmpty then      CurrentUserID := Query.FieldByName('Id').AsInteger    else      raise EXDataHttpUnauthorized.Create('User not found or invalid credentials');  finally    Query.Free;  end;  Result := CurrentUserID;end;function TCRUDService.GetAppointments: TList<TAppointment>;var  Query: TFDQuery;  Appointments: TList<TAppointment>;  CurrentUserID: Integer;begin  Appointments := TList<TAppointment>.Create;  CurrentUserID := GetUserID; // Call the GetUserID function to get the current user's ID  Query := TFDQuery.Create(nil);  try    Query.Connection := FDConnection1;    Query.SQL.Text := 'SELECT * FROM appointments WHERE UserID = :UserID';    Query.ParamByName('UserID').AsInteger := CurrentUserID;    Query.Open;    while not Query.Eof do    begin      var Appointment := TAppointment.Create;      Appointment.ID := Query.FieldByName('ID').AsInteger;      Appointment.UserID := Query.FieldByName('UserID').AsInteger;      Appointment.Company := Query.FieldByName('Company').AsString;      Appointment.Date := Query.FieldByName('Date').AsDateTime;      Appointment.Time := Query.FieldByName('Time').AsDateTime;      Appointments.Add(Appointment);      Query.Next;    end;  finally    Query.Free;  end;  Result := Appointments;end;procedure TCRUDService.AddAppointment(const Appointment: TAppointment);var  Query: TFDQuery;  CurrentUserID: Integer;begin  CurrentUserID := GetUserID; // Retrieve the current user's ID  Query := TFDQuery.Create(nil);  try    Query.Connection := FDConnection1;    Query.SQL.Text := 'INSERT INTO appointments (UserID, Company, Date, Time) VALUES (:UserID, :Company, :Date, :Time)';    Query.ParamByName('UserID').AsInteger := CurrentUserID;    Query.ParamByName('Company').AsString := Appointment.Company;    Query.ParamByName('Date').AsDateTime := Appointment.Date;    Query.ParamByName('Time').AsDateTime := Appointment.Time;    Query.ExecSQL;  finally    Query.Free;  end;end;procedure TCRUDService.UpdateAppointment(const Appointment: TAppointment);var  Query: TFDQuery;  CurrentUserID: Integer;begin  CurrentUserID := GetUserID; // Retrieve the current user's ID  // Ensure the user owns the appointment  Query := TFDQuery.Create(nil);  try    Query.Connection := FDConnection1;    Query.SQL.Text := 'UPDATE appointments SET Company = :Company, Date = :Date, Time = :Time WHERE ID = :ID AND UserID = :UserID';    Query.ParamByName('ID').AsInteger := Appointment.ID;    Query.ParamByName('UserID').AsInteger := CurrentUserID;    Query.ParamByName('Company').AsString := Appointment.Company;    Query.ParamByName('Date').AsDateTime := Appointment.Date;    Query.ParamByName('Time').AsDateTime := Appointment.Time;    Query.ExecSQL;  finally    Query.Free;  end;end;procedure TCRUDService.DeleteAppointment(const ID: Integer);var  Query: TFDQuery;  CurrentUserID: Integer;begin  CurrentUserID := GetUserID; // Retrieve the current user's ID  // Ensure the user owns the appointment  Query := TFDQuery.Create(nil);  try    Query.Connection := FDConnection1;    Query.SQL.Text := 'DELETE FROM appointments WHERE ID = :ID AND UserID = :UserID';    Query.ParamByName('ID').AsInteger := ID;    Query.ParamByName('UserID').AsInteger := CurrentUserID;    Query.ExecSQL;  finally    Query.Free;  end;end;initialization  RegisterServiceType(TCRUDService);end.

Viewing all articles
Browse latest Browse all 3686

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>