2011-10-03 9 views
13

Sto provando a proteggere un controller con l'annotazione @PreAuthorize a livello di tipo e provare a sovrascrivere tale comportamento annotando alcuni metodi con un diverso @PreAuthorize. Tuttavia, il problema è che Spring sta valutando l'annotazione del metodo per prima (accesso concede) e sta quindi valutando l'annotazione della classe (nega l'accesso).L'opzione @PreAuthorize di Spring Security a livello di tipo non può essere ignorata a livello di metodo

C'è un modo per invertire tale ordine? Non riuscivo a capirlo ancora.

Edit:

Al livello di metodo, voglio concedere l'accesso ai soli utenti non registrati:

@PreAuthorize("isAnonymous()") 
@RequestMapping(value = "/create", method = RequestMethod.GET) 
public String renderCreateEntity(ModelMap model) { 
    return userService.renderCreateEntity(model); 
} 

Lo standard per questo controller tuttavia, dovrebbe essere quello di consentire solo agli utenti completamente autenticati:

@Controller 
@RequestMapping(value = "/user") 
@PreAuthorize("isFullyAuthenticated()") 
public class UserController { [...] } 

Quando debug-passo attraverso l'applicazione, noto che isAnonymous() viene valutata per prima e poi isFullyAuthenticated() conseguente in una concessione di diritto di accesso e immediatamente negare l'accesso di nuovo.

+0

Quale versione di Spring Security utilizzi? – beny23

+0

Tutto primavera è 3.0.5.RELEASE – chzbrgla

risposta

11

Grazie per tutte le vostre risposte. La risposta tuttavia era qualcosa di completamente diverso :)

Lo metto qui nel caso in cui qualcun altro abbia gli stessi problemi.

Ho registrato un validatore personalizzato in un metodo annotato @InitBinder. Questo metodo di collegamento è chiamato DOPO la chiamata al metodo richiesta sul controller. E poiché questo metodo di collegamento non è stato annotato con @PreAuthorize, la richiesta è stata respinta.

La soluzione era quella di annotare il metodo di rilegatura in questo modo:

@InitBinder 
@PreAuthorize("permitAll") 
public void initBinder(WebDataBinder binder) { 
    binder.setValidator(validator); 
} 

E poi, il metodo di chiamate dal mio OP valutato come previsto.

5

Il problema non è che è necessario modificare l'ordine di concessione e negare. Il problema è semplice: le annotazioni a livello di metodo ignorano le annotazioni a livello di classe.

PrePostAnnotationSecurityMetadataSource Java Doc:

annotazioni possono essere specificati in classi o metodi e annotazioni specifico metodo ha la precedenza.

L'implementazione concreta di questa logica viene eseguita nel metodo findAnnotation della classe PrePostAnnotationSecurityMetadataSource. (Sfortunatamente questo metodo è privato.)

Così puoi scrivere il tuo MethodSecurityMetadataSource, se dai un'occhiata al codice PrePostAnnotationSecurityMetadataSource, vedrai com'è facile.

Ma un avvertimento alla fine: la fine: compito difficile non riscrivere il metodo, il compito difficile è "iniettare" il nuovo MethodSecurityMetadataSource nel sistema di sicurezza. Credo che non puoi farlo con la configurazione dello spazio dei nomi di sicurezza di primavera, quindi è necessario sostituire lo spazio dei nomi di sicurezza primaverile con la dichiarazione esplicita del bean.

+0

In realtà _WANT_ l'annotazione del livello del metodo per sovrascrivere l'annotazione a livello di classe. Tuttavia, l'annotazione del livello del metodo viene valutata per prima e seconda per livello di classe, in modo che l'annotazione a livello di classe sostituisca effettivamente l'annotazione del metodo. Modificherò qualche esempio nella mia domanda. – chzbrgla

+0

Dai miei test, non è più vero. Se si dispone di un'annotazione di sicurezza a livello di classe e metodo (sia @Secured o @PreAuthorized), entrambi vengono eseguiti. Se l'annotazione del livello del metodo è più restrittiva, va bene. Se è meno restrittivo, allora non funziona. Alla fine ho diviso i miei metodi meno restrittivi in ​​un altro controller. –

Problemi correlati