2013-07-03 9 views
10

ich vorzuauthorisieren die mit Feder Anmerkung wie folgt:Die Verwendung von statischen Variablen im Frühjahr Anmerkungen

@PreAuthorize("hasRole('role')"); 

Allerdings habe ich bereits ‚Rolle‘ definiert als eine statische String auf eine andere Klasse. Wenn ich versuche, diesen Wert zu verwenden:

@PreAuthorize("hasRole(OtherClass.ROLE)"); 

Ich erhalte eine Fehlermeldung:

org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 14): Field or property 'OtherClass' cannot be found on object of type 'org.springframework.security.access.expression.method.MethodSecurityExpressionRoot' 

Gibt es eine Möglichkeit statische Variablen wie diese für den Zugriff mit einer vorzuauthorisieren Anmerkung?

Antwort

16

Versuchen Sie die folgenden, die Frühlings-Expression Language nutzt die Art zu bewerten:

@PreAuthorize("hasRole(T(fully.qualified.OtherClass).ROLE)"); 

Achten Sie darauf, den vollständig qualifizierten Klassennamen angeben.

Documentation

+0

großen Werke, danke! – RobEarl

+0

@RobEarl Awesome froh, ich könnte helfen. Ich habe auch etwas gelernt. –

+0

Works, aber es ist immer noch eine interpretierte Zeichenfolge, so dass es von Eclipse nicht "gesehen" wird, wenn Sie z. der Name, denke ich. – yglodt

3

Probieren Sie etwas wie folgt aus:

@PreAuthorize("hasRole(T(com.company.enumpackage.OtherClass).ROLE.name())"); 

Wenn Ihr Other Enum als public static deklariert wird, dann müssen Sie $ Zeichen verwenden:

@PreAuthorize("hasRole(T(com.company.ParentTopLevelClass$OtherClass).ROLE.name())"); 

name() zu verhindern futer Probleme, wenn toString() später überschrieben wird

4

Die akzeptierte Antwort von Kevin Bowersox funktioniert, aber ich mochte nicht die T (vollqualifizierten.Pfad) Sachen, also schaute ich weiter. Ich begann mit einer benutzerdefinierten Sicherheitsmethode zu schaffen, die Antwort von James Watkins mit hier:

How to create custom methods for use in spring security expression language annotations

jedoch anstelle eines String, habe ich meine enums.Permissions Klasse, die als Parametertyp:

@Component 
public class MySecurityService { 
    public boolean hasPermission(enums.Permissions permission) { 

     ...do some work here... 

     return true; 
    } 
} 

Nun ist der ordentlich Teil ist, dass, wenn ich die hasPermission von einer Anmerkung nennen, muß ich den ganzen Weg nicht eingeben müssen, aber ich habe es in einfachen Anführungszeichen:

@PreAuthorize("@mySecurityService.hasPermission('SOME_ROLE_NAME')") 

Da die Methode "hasPermission" eine Enum erwartet, wird automatisch der Enum-Wert mit diesem Namen gefunden. Wenn es es nicht finden Sie eine Ausnahme erhalten:

org.springframework.expression.spel.SpelEvaluationException: Type conversion problem, cannot convert from java.lang.String to enums.Permissions 

Sie hasPermission zu hasRole umbenennen können, wobei in diesem Fall der einzige Kompromiss ist, dass Sie handeln T (fully.qualified.path) für @mySecurityService und zusätzliche einfache Anführungszeichen.

Nicht sicher, ob es besser ist, aber da ist es. Da nichts davon die Werte zur Kompilierzeit verifizieren wird, besteht mein nächster Schritt darin, einen Annotationsprozessor zu erstellen.

Ich muss auch Kredit, dass der Frühling für den Hinweis auf krosenvold geben kann zu einem Enum automatisch konvertieren: https://stackoverflow.com/a/516899/618881

6

Um es möglich zu machen Ausdrücke ohne Paketnamen zu schreiben:

<sec:global-method-security> 
    <sec:expression-handler ref="methodSecurityExpressionHandler"/> 
</sec:global-method-security> 

<bean id="methodSecurityExpressionHandler" class="my.example.DefaultMethodSecurityExpressionHandler"/> 

Dann verlängern die DefaultMethodSecurityExpressionHandler:

public class DefaultMethodSecurityExpressionHandler extends org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler { 

    @Override 
    public StandardEvaluationContext createEvaluationContextInternal(final Authentication auth, final MethodInvocation mi) { 
     StandardEvaluationContext standardEvaluationContext = super.createEvaluationContextInternal(auth, mi); 
     ((StandardTypeLocator) standardEvaluationContext.getTypeLocator()).registerImport("my.example"); 
     return standardEvaluationContext; 
    } 
} 

Jetzt my.example.Roles.java erstellen:

public class Roles { 

    public static final String ROLE_UNAUTHENTICATED = "ROLE_UNAUTHENTICATED"; 

    public static final String ROLE_AUTHENTICATED = "ROLE_AUTHENTICATED"; 
} 

und bezeichnen es ohne Paketnamen in Anmerkungen:

@PreAuthorize("hasRole(T(Roles).ROLE_AUTHENTICATED)") 

statt:

@PreAuthorize("hasRole(T(my.example.Roles).ROLE_AUTHENTICATED)") 

macht es besser lesbar imho. Auch Rollen sind jetzt getippt. Schreiben:

@PreAuthorize("hasRole(T(Roles).ROLE_AUTHENTICATEDDDD)") 

und wird beim Starten des Systems Fehlermeldungen erhalten, die es nicht gewesen wäre, wenn Sie schrieb:

@PreAuthorize("hasRole('ROLE_AUTHENTICATEDDDD')") 
+0

Gute Lösung. Startup-Fehler wären nett, aber ich denke nicht, dass Sie das so erreichen können. Die Auswertung erfolgt weiterhin zur Laufzeit. Habe noch keine bessere Lösung gefunden aber zäh ... – chris

Verwandte Themen