그중에서 @PreAuthorize, @PostAuthorize Annotation의 경우에는 SpringEL에서 제공하는 Expression 이외에도 사용자가 정의한 Custom Expression(Method)를 호출할 수 있는 기능을 제공한다.
해당 기능에 대해서 알아보도록 하자.
@PreAuthorize("isAuthenticated() and (( #user.name == principal.name ) or hasRole('ROLE_ADMIN'))")
@RequestMapping( value = "", method = RequestMethod.PUT)
public ResponseEntity<Project> updateProject( User user ){
updateProject.update( user );
return new ResponseEntity<Project>( new Project(), HttpStatus.OK );
}
우선 위의 예제와 같이 isAuthenticated, hasRole과 같은 Spring EL에서 기본제공하는 기능을 활용할 수도 있다.
다만, 사용자가 원하는 기능이 기본으로 제공하는 기능에 존재하지 않는 경우에는 문제가 될 수 있다.
이러한 경우를 커버하기 위해서 Spring Security에서는 Custom Expression을 사용할 수 있는 기능을 열어 두었다.
Component 생성
먼저, Custom Expression(Method)를 정의할 Component를 생성한다.
// @Service
@Component("loginService")
public class LoginService {
public boolean pageReadRoleCheck() {
return true;
}
}
@PreAuthorize, @PostAuthorize Annotation에서 사용
@GetMapping("/api/v1/projects")
@PreAuthorize("@loginService.pageReadRoleCheck()")
public List<ProjectResponseDto> getProjectList() {
return projectService.findAll();
}
위와 같이 간단하게 Custom Expression을 Spring Security Annotation에서 사용이 가능하다.
Param 정보 전달
추가적으로, Custom Expression에 필요한 정보를 Param으로 넘길 수도 있다.
#pj와 같이 사용하여 Annotation이 붙은 Method의 Param 정보도 전달 할 수 있다.
// @Service
@Component("loginService")
public class LoginService {
public boolean pageReadRoleCheck(String id) {
return true;
}
}
/////
@GetMapping("/api/v1/projects")
@PreAuthorize("@loginService.pageReadRoleCheck(#pj.id)")
public List<ProjectResponseDto> getProjectList(Project pj) {
return projectService.findAll();
}
returnObject
@PostAuthorize의 경우에는 해당 Method의 수행 결과 값도 전달 할 수 있다.
returnObject라는 예약어를 사용하면 된다.
@PostAuthorize("@loginService.pageReadRoleCheck(returnObject.name)")
@RequestMapping( value = "/{id}", method = RequestMethod.GET )
public Project getProject( @PathVariable("id") long id ){
return service.findOne(id);
}
Annotation 활성화 설정 추가
마지막으로, 이러한 Annotation을 활성화 시키기 위해서는 설정을 추가해 주어야 한다.
@PreAuthorize("isAuthenticated() and (( #user.name == principal.name ) or hasRole('ROLE_ADMIN'))")
@RequestMapping( value = "", method = RequestMethod.PUT)
public ResponseEntity<Project> updateProject( User user ){
updateProject.update( user );
return new ResponseEntity<Project>( new Project(), HttpStatus.OK );
}
@PreAuthorize
추가적으로 @PreAuthorize 내에 #user.name를 사용한 부분을 보면
Annotation이 붙은 Method의 Param값을 위와 같이 활용하여 사용할 수 있게 된다.
@PostAuthorize
@PostAuthorize의 경우에는 Method가 실행된 이후의 return값을 활용할 수 있다.
아래와 같이 returnObject.name과 같이 "returnObject"를 사용하면 된다.
@PostAuthorize("isAuthenticated() and (( returnObject.name == principal.name ) or hasRole('ROLE_ADMIN'))")
@RequestMapping( value = "/{id}", method = RequestMethod.GET )
public Project getProject( @PathVariable("id") long id ){
return service.findOne(id);
}
Annotation 활성화 설정 추가
추가적으로, 이러한 Annotation을 활성화 시키기 위해서는 설정을 추가해 주어야 한다.