2012-09-26 12 views
5

Qual è il modo corretto per proteggere @RequestBody con Spring Security?Spring Securing @RequestBody

Ad esempio: Un User può avere più Blog s ed ogni Blog può avere molteplici Entry s. Un utente va per salvare una voce a un certo blog e la richiesta sarebbe venuto in questo modo:

@RequestMapping(value="/api/entry", method=RequestMethod.POST) 
@ResponseBody 
public Entry save(@Valid @RequestBody Entry entry) { 
    this.entryService.save(entry); 
    return entry; 
} 

Ora, l'ingresso entry ha un Blog, l'utente potrebbe avere falsificato la richiesta e scelto qualcun altro blog, pubblicare in modo efficace la voce sul proprio blog. Anche se potrei capirlo in convalida (interrogare il livello di persistenza per verificare che lo Blog appartenga al login User) Ritengo che questo debba essere gestito da Spring Security. Se è così, come faccio a fare questo?

risposta

6

Abbiamo avuto questo tipo di situazione.

Ecco la soluzione. Non mi è piaciuta molto

@RequestMapping(value="/api/entry", method=RequestMethod.POST) 
@ResponseBody 
@PreAuthorize("#entry.author.name == principal.name)" 
public Entry save(@Valid @RequestBody Entry entry, Principal principal) { 
    this.entryService.save(entry); 
    return entry; 
} 

o

@RequestMapping(value="/api/entry", method=RequestMethod.POST) 
    @ResponseBody 
    @PreAuthorize("Decision.isOK(entry, principal)") 
    public Entry save(@Valid @RequestBody Entry entry, Principal principal) { 
     this.entryService.save(entry); 
     return entry; 
    } 

// In questo caso Primavera chiamerà il metodo statico Isok() dalla classe decisione. Dovrebbe tornare booleano.

Spring injects Oggetto principale principale oggetto autorizzato per il metodo, non devi preoccuparti di questo. Abilita @PreAuthorize annotazione con

<security:global-method-security pre-post-annotations="enabled" />

secondo utilizzando Aspect. Crea aspetto.

@Retention(RetentionPolicy.RUNTIME) 
@Target(ElementType.METHOD) 
public @interface Protector { 
} 

@Aspect 
@Component 
public class MyAspect { 
    @Before("@annotation(com.xyz.Protector)") 
    public void before(JoinPoint joinPoint) throws Throwable { 
     //u can get method object from joinPoint object, 
     Method method = ((MethodSignature)joinPoint.getMethodSignature()).getMethod(); 
     //As long as you have Method object you can read the parameter objects (Entry and Principal) with reflection. 
     //So Compare here: If entry.getOwner().getId().equal(principal.getName()) blah blah blah 
    } 
} 

@RequestMapping(value="/api/entry", method=RequestMethod.POST) 
@ResponseBody 
@Protector 
public Entry save(@Valid @RequestBody Entry entry, Principal principal) { 
    this.entryService.save(entry); 
    return entry; 
} 

Se hai aspetto si può avere più possedere il tempo di esecuzione

Fare riferimento a questo ulr

+1

Dopo aver provato entrambi gli approcci sono stato più felice con '@ PreAuthorize'. Per chiunque altro si è imbattuto in questo, la sicurezza del req body è stata alquanto complessa per me e ho potuto legare un bean con alcuni servizi. L'EL cambia leggermente quando si chiama un'istanza di bean. Esempio: '@PreAuthorize (" @ decision.isOK (# entry.blog.id, principal) ")' –

+1

Sono felice che abbia aiutato :) '@ PreAuthorize' è esattamente per questo scopo, mentre @Aspect è più generale:) – Elbek

+0

I parametri del metodo di riferimento da Spring-EL in @PreAuthorize devono essere preceduti da un prefisso '' '' # '' '' '. '' '' @PreAuthorize ("Decision.isOK (#entry, #principal)") '' '' invece di '' '' @PreAuthorize ("Decision.isOK (entry, principal)") '' ''. –

Problemi correlati