AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren

Attribute einer Methode in Methode abfragen

Ein Thema von hschmid67 · begonnen am 3. Feb 2018 · letzter Beitrag vom 13. Aug 2019
Antwort Antwort
hschmid67

Registriert seit: 2. Jul 2012
32 Beiträge
 
Delphi 10.2 Tokyo Enterprise
 
#1

Attribute einer Methode in Methode abfragen

  Alt 3. Feb 2018, 11:37
Delphi-Version: 5
Hallo Zusammen,

ich wäre froh, wenn mir jemand bei einer Verständnisfrage zu Attributen helfen könnte.
Ich möchte gerne in einer eigene Klasse Methoden durch Attribute so kennzeichnen, dass sie nur bestimmte User ausführen dürfen.

(habe mal wieder vergessen, die Delphi-Version umzustellen: Habe nicht Delphi 5 sondern Tokyo Pro)


Ich habe mir in etwa folgenden Pseudo-Code vorgestellt:

Delphi-Quellcode:
TmyClass = class
  [RightAttribute('Special')]
  procedure DoSpecialJob;
end;

procedure TmyClass.DoSpecialJob;
begin
  if not CurrentUserHasRight(RightOfMethod) then
    raise Exception.Create('Method not allowed for user');

  // eigentlicher Code der Methode
end;
Ich weiß nun leider nicht, wie ich mit "RightOfMethod" die Attribute der gerade ausgeführten Methode abfragen kann.

Man könnte natürlich das Attribut weglassen und gleich in die Methode schreiben, aber eigentlich fände ich es eleganter, wenn solche Attribute/Konfigurationen im Interface-Teil stünden und nicht in der Implementation.

Also, ersatzweise ging sonst in der Implementation auch

Delphi-Quellcode:
procedure TmyClass.DoSpecialJob;
begin
  if not CurrentUserHasRight('Special') then
    raise Exception.Create('Method not allowed for user');

  // eigentlicher Code der Methode
end;
Beginne gerade, mit Attributen zu experimentieren - und vielleicht habe ich das eine oder andere noch nicht ganz verstanden. Deshalb wäre ich für jeden Hinweis dankbar. Oder im konkreten Fall auch für eine andere Lösung des Problems

Viele Grüße
Harald
Harald
  Mit Zitat antworten Zitat
Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
4.626 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#2

AW: Attribute einer Methode in Methode abfragen

  Alt 3. Feb 2018, 17:52
Bin auch kein Profi, was die Attribute angeht, deshalb kann ich dir leider nicht sagen, ob es über die RTTI einen "eleganten" (wenn man RTTI überhaupt als elegant bezeichnen darf) Weg gibt, aber ich befürchte, ohne zumindest den Namen der Methode nochmal explizit darin aufzuführen bzw an die CurrentUserHasRight Funktion zu übergeben, wird es recht umständlich bis unmöglich.

Hauptproblem dürfte sein die Adresse der aktuellen Methode zu ermitteln, um dann deren RTTI Infos abfragen zu können. Eine Möglichkeit wäre eine "Wrapper-Funktion", welche die eigentliche Methode aufruft und vorher den Check ausführt (wird allerdings schon wieder sehr umständlich, wenn die Zielmethoden unterschiedliche Parameter und Rückgabewerte besitzen). Alternativ könntest du per inline Assembly den aktuellen EIP ermitteln und gegen die VTable der Objektinstanz abgleichen (um durch unterschiedliche Anzahl von Parametern bedingte Varianz zu kompensieren). Aber auch das ist ziemlich hacky und zudem nicht für 64-Bit möglich.

Edit:
Noch ein paar andere Gedanken und Methoden dazu hier:
https://stackoverflow.com/questions/...hi-as-a-string
https://stackoverflow.com/questions/...me-in-delphi-7
Projekte:
- GitHub (Profil, zyantific)
- zYan Disassembler Engine ( Zydis Online, Zydis GitHub)
  Mit Zitat antworten Zitat
hschmid67

Registriert seit: 2. Jul 2012
32 Beiträge
 
Delphi 10.2 Tokyo Enterprise
 
#3

AW: Attribute einer Methode in Methode abfragen

  Alt 3. Feb 2018, 18:34
Vielen Dank für die Ideen und das Mitdenken. Hmmm, so ganz verstehe ich die Attribute noch nicht wirklich. Habe in einem anderen Thread (http://www.delphipraxis.net/175701-w...ibute-gut.html) das hier gefunden:

Von Uwe Raabe:
http://www.delphipraxis.net/1221409-post3.html

und der verweist hier auf eine Info vom der Emarcadero-Hilfe

http://docwiki.embarcadero.com/RADSt...sierung#Rollen

Wo in Datasnap scheinbar genau sowas gemacht wird, was ich im Sinn hatte:

Delphi-Quellcode:
 TServerMethods1 = class(TComponent)
 public
   [TRoleAuth('admin')]
   function EchoString(Value: string): string;
   function ReverseString(Value: string): string;
 end;
Doch wenn ich das richtig verstehe, hilft mir das nur, wenn ich eine Methode habe, aus der heraus

TServerMethods1.EchoString(Value: string): string;

aufgerufen wird. Denn in dieser Methode - also von außerhalb TServerMethods1 und außerhalb von EchoString kann man über RTTI abfragen, welche Attribute zu TServerMethod1.EchoString gehören. Und dann kann man entscheiden lassen, ob der Aufruf stattfinden soll, oder eben nicht.

Wenn man aber schon in der Methode TServerMethod1.EchoString drin ist, mag wohl wirklich nur der Weg über die Adresse gangbar sein - und das ist ja viel komplizierter, als wenn ich tatsächlich gleich meine Rechte/Rollen in der Implementation der Methode abfrage. Damit bringen mir in diesem Fall wohl die Attribute nichts.

Aber vielleicht versteh ich ja das Ganze nicht wirklich und jemand kann noch etwas Licht hineinbringen?

Für jeden Hinweis dankbar
Harald
Harald
  Mit Zitat antworten Zitat
Der schöne Günther

Registriert seit: 6. Mär 2013
4.958 Beiträge
 
Delphi 10 Seattle Enterprise
 
#4

AW: Attribute einer Methode in Methode abfragen

  Alt 3. Feb 2018, 19:49
Ich hatte genau den gleichen Gedanken in vor längerer Zeit auch [1]. Auch hier hatte ich die Idee das mit Attributen festzulegen.

Letzten Endes sind wir damit echt nicht glücklich geworden. Nicht nur hat das im eigentlichen Quelltext nichts zu suchen: Klasse X kümmert sich um eine bestimmte Aufgabe, gut ist. Welcher Benutzer zu welcher Uhrzeit bei welcher Mondkonstellation was aufrufen darf sind echt cross-cutting concerns.

Vor allem schmälert das die Wiederverwendbarkeit - Vielleicht kannst du genau die gleiche Klasse in einer anderen Anwendung gebrauchen, aber entweder gibt es hier keins oder ein völlig anderes Rechtesystem.

Wir haben das so umgesetzt dass die ganze Rechte-Geschichte völlig simpel ist: Jede Aktion hat eine String-ID, und zu diesem String lässt sich nachschlagen welcher "Benutzerleven" das aufrufen darf. Darum kümmert sich derjenige der die Methode aufruft, in der Regel ist das ein Bestandteil der Oberfläche. Ganz vereinfacht:

Delphi-Quellcode:
Unit Permissions.IDs;

interface
   const SPECIAL_JOB = 'SPECIAL_JOB';
specialJobButton.Enabled := rightsManager.canInvoke(currentUser, SPECIAL_JOB);


Möchtest du die Rechte-Validierung trotzdem direkt in die Klasse selbst packen hier ein paar Gedanken:

Namen der aktuellen Methode bestimmen
Die Sache hat sicher noch einen Haken, aber mit einem TVirtualMethodInterceptor aus System.Rtti könnte man das machen:

Delphi-Quellcode:
uses
  System.SysUtils,
  System.Rtti;

type
   TMyObject = class
      private var
         interceptor: TVirtualMethodInterceptor;
      private
         procedure handleBefore(
            Instance: TObject;
            Method: TRttiMethod;
            const Args: TArray<TValue>;
            out DoInvoke: Boolean;
            out Result: TValue
         );
         procedure handleAfter(
            Instance: TObject;
            Method: TRttiMethod;
            const Args: TArray<TValue>;
            var Result: TValue
         );
      protected var
         currentMethodName: String;
      public
         constructor Create();
         destructor Destroy(); override;
         procedure IKnowMyName(); virtual;
         procedure IDoNotKnowMyName();
   end;

constructor TMyObject.Create();
begin
   inherited Create();
   interceptor := TVirtualMethodInterceptor.Create( ClassType() );
   interceptor.OnBefore := handleBefore;
   interceptor.OnAfter := handleAfter;
   interceptor.Proxify(self);
end;

destructor TMyObject.Destroy();
begin
   if Assigned(interceptor) then
      begin
         interceptor.Unproxify(self);
         interceptor.Destroy();
      end;
   inherited Destroy();
end;

procedure TMyObject.handleBefore(
   Instance: TObject;
   Method: TRttiMethod;
   const Args: TArray<TValue>;
   out DoInvoke: Boolean;
   out Result: TValue
);
begin
   DoInvoke := True;
   currentMethodName := Method.Name;
end;

procedure TMyObject.handleAfter(
   Instance: TObject;
   Method: TRttiMethod;
   const Args: TArray<TValue>;
   var Result: TValue
);
begin
   currentMethodName := EmptyStr;
end;

procedure TMyObject.IKnowMyName();
begin
   WriteLn( currentMethodName.QuotedString() );
end;

procedure TMyObject.IDoNotKnowMyName();
begin
   WriteLn( currentMethodName.QuotedString() );
end;

Ebenfalls kannst du deine Methode mit dem Exception werfen verwenden: Der TVirtualMethodInterceptor hat ein OnException-Event: Wenn deine spezielle Exception geworfen wurde könnte er die schlucken und deine Methode tut einfach überhaupt nichts.

Analog hat das OnBefore-Event ja auch den Parameter Method: TRttiMethod . Es gibt TRttiMethod.GetAttributes() ! Hier kannst du dir alle Attribute der aktuell aufgerufenen Methode anschauen. Damit kämst du auch ans Ziel.


Nur wie gesagt, ich persönlich würde es so nicht mehr machen. So etwas gehört nicht in die eigentliche Klasse, das "verschmutzt" nur den eigentlichen Code.



[1] http://www.delphipraxis.net/175990-b...en-rechte.html
  Mit Zitat antworten Zitat
hschmid67

Registriert seit: 2. Jul 2012
32 Beiträge
 
Delphi 10.2 Tokyo Enterprise
 
#5

AW: Attribute einer Methode in Methode abfragen

  Alt 4. Feb 2018, 15:34
Vielen Dank für Eure Antworten und Gedanken! Ich bin wieder einmal beeindruckt, wie sehr ich von Euren Ideen und Erfahrungen hier in der DP profitieren kann.

Gerade die Frage, ob's meine Idee (die ja nicht so neu zu sein scheint) wirklich bringt, oder es nicht bessere Wege zu diesem Ziel gibt, ist mir wirklich wertvoll - vor allem, da sie ja aus Euren eigenen Erfahrungen heraus kommt.

Also, ich überlege mir das Ganze nochmal, ob an dieser meiner Stelle Attribute wirklich das Mittel der Wahl sind.

Viele Grüße
Harald
Harald
  Mit Zitat antworten Zitat
Sequitar

Registriert seit: 8. Jan 2016
40 Beiträge
 
Delphi 10.3 Rio
 
#6

AW: Attribute einer Methode in Methode abfragen

  Alt 13. Aug 2019, 17:35
thread schon etwas älter, aber ich häng mich hier mal mit einem follow-up dran.

habe zurzeit mal mit dem TVirtualMethodInterceptor experimentiert, was auch sehr gut klappt. Allerdings habe ich mit groben speicherlöchern zu tun, falls ich zum bleistift die RTTI-Attribute einer methode abfragen möchte um die dann zu intercepten:

Delphi-Quellcode:
Procedure Dopassword(Instance: Tobject; Method: Trttimethod;
  Const Args: TArray<TValue>; Out DoInvoke: Boolean; Out Result: TValue);
Var
  Pw: String;
  attr:tcustomattribute;
  //Attributes: Tarray<Tcustomattribute>;
Begin
if True then

  Doinvoke := True;
  Begin
    attributes:= Method.GetAttributes Do; //<<<< produziert bei mir ein speicherleck, auch wenn ich erst das getattribute einer (lokalen)tarray-variable zuweise
    //For {Var //inline ab 10.1} Attr In Attributes Do
    //If Attr Is Passwordprotectedattribute
    //Then
//do some checks>> einfach mal so eingefügt als beispiel:
    //Begin
    //Writeln('change password protected.');
    //Readln(Pw);
    //If Pw <> 'login'
    //Then
    //Doinvoke := False;
    //End;
  End;
  //Setlength(Attributes, 0);
End;
Ist das normal? (abgesehen davon dass Lecks nicht "normal" sein sollten), kann ich das umgehen?
  Mit Zitat antworten Zitat
Der schöne Günther

Registriert seit: 6. Mär 2013
4.958 Beiträge
 
Delphi 10 Seattle Enterprise
 
#7

AW: Attribute einer Methode in Methode abfragen

  Alt 13. Aug 2019, 18:26
Ich kann das nicht nachvollziehen. Hast du ein funktionsfähiges Testprogramm?

Ich bekomme hier keine Speicherlecks:

Delphi-Quellcode:
// JCL_DEBUG_EXPERT_GENERATEJDBG OFF
// JCL_DEBUG_EXPERT_INSERTJDBG OFF
program AtrtibTestProject;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  FastMM4,
  System.SysUtils,
  System.Rtti;

type
   MyAttribute = class(TCustomAttribute);

   TMyObject = class(TObject)
      public
         [MyAttribute]
         procedure test(); virtual;
   end;

procedure p();
var
   interceptor: TVirtualMethodInterceptor;
   myObject: TMyObject;
begin
   interceptor := nil; myObject := nil;
   try
      myObject := TMyObject.Create();
      interceptor := TVirtualMethodInterceptor.Create( myObject.ClassType() );
      interceptor.OnBefore :=
         procedure(
            instance:   TObject;
            method:      TRttiMethod;
            const args: TArray<TValue>;
            out doInvoke: Boolean;
            out result: TValue
         )
         var
            attributes: TArray<TCustomAttribute>;
         begin
            attributes := method.GetAttributes();
            WriteLn('We found ', Length(attributes), ' attributes');

         end;
      interceptor.Proxify(myObject);

      myObject.test();
   finally
      if Assigned(interceptor) then
         begin
            interceptor.Unproxify(myObject);
            interceptor.Destroy();
            end;
      myObject.Free();
   end;
end;


{ TMyObject }

procedure TMyObject.test();
begin
   WriteLn('Hello World');
end;

begin
   ReportMemoryLeaksOnShutdown := True;
   try
      p();
   except
      on E: Exception do
         Writeln(E.ClassName, ': ', E.Message);
   end;
   readln;
end.
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 08:17 Uhr.
Powered by vBulletin® Copyright ©2000 - 2019, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2019 by Daniel R. Wolf