2012-09-26 22 views
5

¿Cuál es la forma correcta de asegurar el @RequestBody con Spring Security?Fijación de muelles @ Cuerpo de solicitud

Por ejemplo: Un User puede tener múltiples Blog s y cada Blog puede tener múltiples Entry s. Un usuario va a guardar una entrada a un determinado blog y la solicitud vendría en este aspecto:

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

Ahora, el entrante entry tiene un Blog, el usuario podría haber adulterado la petición y elegido algún otro blog, efectivamente publicando la entrada a su blog. Aunque pude detectar esto en la validación (consultar la capa de persistencia para verificar que Blog pertenece a la sesión User), creo que esto debería ser manejado por Spring Security. Si es así, ¿cómo hago esto?

Respuesta

6

Tuvimos este tipo de situación.

Aquí está la solución dos. No me gustaba mucho

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

// En ese caso, la primavera va a llamar a su método estático Isok() de la clase Decisión. Debería devolver boolean.

Inyector de resorte Objeto autorizado principal principal para el método, no tiene que preocuparse por ello. Habilitar @PreAuthorize anotación con

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

Segundo Uso de aspecto. Crear aspecto.

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

Si tiene aspecto que puede tener más la posesión en tiempo de ejecución

Consulte también este ulr

+1

Después de probar los dos enfoques que más me contento con '@ PreAuthorize'. Para cualquier otra persona que se encuentre con esto, asegurar el cuerpo de la solicitud fue algo complejo para mí y pude conectar un bean con algunos servicios. El EL cambia ligeramente cuando se llama a una instancia de bean. Ejemplo: '@PreAuthorize (" @ decision.isOK (# entry.blog.id, principal) ")' –

+1

Estoy feliz de que haya ayudado :) '@ PreAuthorize' es exactamente para este propósito, mientras que @Aspect es más general:) – Elbek

+0

Los parámetros del método de referencia de un Spring-EL en @PreAuthorize deben ir precedidos de un '' '' # '' '' agudo. '' '' @PreAuthorize ("Decision.isOK (#entry, #principal)") '' '' en lugar de '' '' @PreAuthorize ("Decision.isOK (entry, principal)") '' ''. –

Cuestiones relacionadas