Come creare metodi personalizzati da utilizzare nelle annotazioni della lingua delle espressioni di sicurezza di spring

Vorrei creare una class che aggiunga metodi personalizzati da utilizzare nel linguaggio delle espressioni di sicurezza primarie per l’authorization basata su metodi tramite annotazioni.

Ad esempio, mi piacerebbe creare un metodo personalizzato come “customMethodReturningBoolean” da utilizzare in qualche modo come questo:

@PreAuthorize("customMethodReturningBoolean()") public void myMethodToSecure() { // whatever } 

La mia domanda è questa. Se è ansible, quale class dovrei sottoclass per creare i miei metodi personalizzati, come potrei fare per configurarlo nei file di configurazione xml primaverili e venire qualcuno a darmi un esempio di un metodo personalizzato usato in questo modo?

Avrai bisogno di sottoclassare due classi.

Innanzitutto, imposta un nuovo gestore di espressioni del metodo

    

myMethodSecurityExpressionHandler sarà una sottoclass di DefaultMethodSecurityExpressionHandler che sovrascrive createEvaluationContext() , impostando una sottoclass di MethodSecurityExpressionRoot su MethodSecurityEvaluationContext .

Per esempio:

 @Override public EvaluationContext createEvaluationContext(Authentication auth, MethodInvocation mi) { MethodSecurityEvaluationContext ctx = new MethodSecurityEvaluationContext(auth, mi, parameterNameDiscoverer); MethodSecurityExpressionRoot root = new MyMethodSecurityExpressionRoot(auth); root.setTrustResolver(trustResolver); root.setPermissionEvaluator(permissionEvaluator); root.setRoleHierarchy(roleHierarchy); ctx.setRootObject(root); return ctx; } 

Nessuna delle tecniche menzionate funzionerà più. Sembra che Spring abbia fatto grandi sforzi per impedire agli utenti di scavalcare SecurityExpressionRoot.

EDIT 11/19/14 Imposta Spring per utilizzare le annotazioni di sicurezza:

  ...  

Crea un bean come questo:

 @Component("mySecurityService") public class MySecurityService { public boolean hasPermission(String key) { return true; } } 

Quindi fai qualcosa di simile nel tuo jsp:

    

Oppure annota un metodo:

 @PreAuthorize("@mySecurityService.hasPermission('special')") public void doSpecialStuff() { ... } 

E ricorda: se stai usando Spring e devi risolvere un problema estendendo le classi, sovrascrivendo metodi, implementando interfacce, ecc … allora probabilmente stai facendo qualcosa di sbagliato. Sono tutte annotazioni e xml, ecco perché amiamo tanto Spring e non (vecchie versioni di) EJB.

Inoltre, è ansible utilizzare Spring Expression Language nelle proprie annotazioni @PreAuthorize per accedere all’autenticazione corrente e agli argomenti del metodo.

Per esempio:

 @Component("mySecurityService") public class MySecurityService { public boolean hasPermission(Authentication authentication, String foo) { ... } } 

Quindi aggiorna @PreAuthorize in modo che corrisponda alla nuova firma del metodo:

 @PreAuthorize("@mySecurityService.hasPermission(authentication, #foo)") public void doSpecialStuff(String foo) { ... } 

Grazie ericacm , ma non funziona per alcuni motivi:

  • Le proprietà di DefaultMethodSecurityExpressionHandler sono private (kludges di visibilità riflessione indesiderabili)
  • Almeno in Eclipse, non riesco a risolvere un object MethodSecurityEvaluationContext

Le differenze sono che chiamiamo il metodo createEvaluationContext esistente e quindi aggiungiamo il nostro object radice personalizzato. Infine ho appena restituito un tipo di object StandardEvaluationContext poiché MethodSecurityEvaluationContext non si risolverebbe nel compilatore (sono entrambi dalla stessa interfaccia). Questo è il codice che ora ho in produzione.

Crea MethodSecurityExpressionHandler usa la nostra root personalizzata:

 public class CustomMethodSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler { // parent constructor public CustomMethodSecurityExpressionHandler() { super(); } /** * Custom override to use {@link CustomSecurityExpressionRoot} * * Uses a {@link MethodSecurityEvaluationContext} as the EvaluationContext implementation and * configures it with a {@link MethodSecurityExpressionRoot} instance as the expression root object. */ @Override public EvaluationContext createEvaluationContext(Authentication auth, MethodInvocation mi) { // due to private methods, call original method, then override it's root with ours StandardEvaluationContext ctx = (StandardEvaluationContext) super.createEvaluationContext(auth, mi); ctx.setRootObject( new CustomSecurityExpressionRoot(auth) ); return ctx; } } 

Sostituisce la root predefinita estendendo SecurityExpressionRoot . Qui ho rinominato hasRole con hasntitlement:

 public class CustomSecurityExpressionRoot extends SecurityExpressionRoot { // parent constructor public CustomSecurityExpressionRoot(Authentication a) { super(a); } /** * Pass through to hasRole preserving Entitlement method naming convention * @param expression * @return boolean */ public boolean hasEntitlement(String expression) { return hasRole(expression); } } 

Infine aggiorna securityContext.xml (e assicurati che sia referenziato dal tuo applcationContext.xml):

       

Nota: l’annotazione @Secured non accetterà questa sovrascrittura mentre viene eseguita attraverso un gestore di convalida differente. Quindi, nel suddetto xml li ho disabilitati per prevenire successive confusioni.