2012-09-26 1 views
5

Was ist der richtige Weg, um die @RequestBody mit Spring Security zu sichern?Federsicherung @RequestBody

Zum Beispiel: Ein User können mehrere Blog s haben und jede Blog können mehrere Entry s haben. Ein Benutzer geht um einen Eintrag zu einem bestimmten Blog zu speichern und die Anforderung wie diese kommen in würde:

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

nun die eingehenden entry ein Blog hat, haben die Benutzer die Anforderung frisiert könnte und jemand anderes Blog gewählt, effektiv den Eintrag in ihrem Blog veröffentlichen. Obwohl ich dies in der Validierung (Abfrage der Persistenzschicht, um zu überprüfen, dass die Blog gehört zu den angemeldeten User) Ich denke, dass dies von Spring Security behandelt werden sollte. Wenn ja, wie gehe ich vor?

Antwort

6

Wir hatten diese Art von Situation.

Hier ist die zwei Lösung. Ich wusste nicht, wie viel

@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; 
} 

oder

@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 diesem Fall Frühling wird Ihre statische ISOK() -Methode von der Entscheidung Klasse aufrufen. Es sollte Boolean zurückgeben.

Spring injects Prinzipal autorisiertes Objekt für die Methode, Sie müssen sich keine Sorgen machen. aktivieren @PreAuthorize Annotation mit

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

Zweiter Aspekt verwenden. Erstellt einen Aspekt.

@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; 
} 

Wenn Sie Aspekt haben, können Sie mehr zur Laufzeit zu besitzen haben

diese ulr

+1

Siehe auch beiden Ansätze Nach dem Versuch, ich war sehr zufrieden mit '@ PreAuthorize'. Für irgendjemand anderen, der auf dieses Problem gestoßen ist, war die Sicherung der Anforderung für mich ziemlich komplex und ich konnte eine Bean mit einigen Diensten verbinden. Die EL ändert sich geringfügig, wenn eine Bean-Instanz aufgerufen wird. Beispiel: '@PreAuthorize (" @ decision.isOK (# entry.blog.id, principal) ")' –

+1

Ich bin froh, dass es geholfen hat :) '@ PreAuthorize' ist genau für diesen Zweck, während @aspect allgemeiner ist:) – Elbek

+0

Reference-Methode Parameter von einem Spring-EL in @ PreAuthorize sollte mit einem scharfen '' '' # '' '' vorangestellt werden. '' '' @ PreAuthorize ("Decision.isOK (#entry, #principal)") '' '' anstelle von '' '' @ PreAuthorize ("Decision.isOK (entry, principal)") '' ''. –