- Spring Security에서 메소드 레벨 보안은 기본적으로 비활성화 되어있다.
- 메소드 레벨 보안의 활성화를 위해선 @EnableMethodSecurity라는 어노테이션을 사용해야한다.
- 해당 어노테이션은 클래스 위에 선언하여 메소드레벨 보안을 활성화시킬 수 있다.
- 해당 어노테이션 이외에도 다른 어노테이션들이 필요하다. 첫 번재 세트는 @preAuthorize, @postAuthorize이다.
- 위의 어노테이션들을 사용하기 위해선 @EnableMethodSecurity 내부에서 (prePostEnabled =true)로 설정해야한다.
- @Secured를 사용하기 위해선 securedEnabled =ture, @RoleAllowed를 사용하기 위해선 jsr250Enabled = true로 설정해야한다.
- 메소드 레벨 보안은 리포지토리, 컨트롤러, 서비스 모두에 적용이 가능하다
- preAuthorize는 메소드가 호출되는 순간 조건을 비교하여, 조건에 부합하지 않는다면 메소드 호출 자체를 무효화 시킨다.
@preAuthorize("hasAuthority('VIEWLOANS')")
@preAuthorize("hasRole('ADMIN')")
@preAuthorize("hasRole('USER')")
@preAuthorize("# username == authentication.principal.username") //입력받은 유저네임과 인증객체에 저장 유저네임이 동일한지 확인하는 로직
public Loan getLoanDetails(String username){
return loansRepository.loadLoanDetailsByUserName(username);
}
- 위와같이 여러가지 조건을 명시했을 경우 위의 조건들 중 하나라도 충족하면 밑의 클래스를 실행시킬 수 있다 즉 or의 개념으로 동작한다.
- postAuthorize는 메소드의 호출을 막지않고 실행시킨다 다만, 메소드의 리턴값을 검사하여 조건에 부합하지 않는다면 리턴을 취소시킨다.
@postAuthorize("returnObject.username == authentication.principal.username")
@postAuthorize("hasPermission(returnObject,'ADMIN')")
public Loan getLoanDetails(String username){
return loansRepository.loadLoanDetailsByUserName(username);
}
- 요구사항이 너무 복잡하면 PermissionEvaluator라는 인터페이스를 implements하여 로직을 작성하도록 하자.
- 위의 메소드 레벨 보안은 Spring AOP에 의해 실현된다. 런타임 도중 메소드 호출을 인터셉트하여 주석 내의 조건을 먼저 검사하는것이다
- Authorize는 권한을 체크하는 메소드레벨 보안이다.
- 우선 자바 메인 어플리케이션에 주석을 달아줘야한다.
@EnableMethodSecurity(prePostEnabled = true, securedEnabled =true, jsr250Enabled= true)
public class MainApplication{
- 리포지토리에 preAuthorize를 적용해 보겠다
@Repository
public interface LoanRepository extends CrudRepository<Loans, Long> {
@preAuthorize("hasRole(ROOT)")
List<Loans> findByCustomerIdOrderByStartDtDesc(int customerId);
}
- 다음과 같이 findByCustomerIdOrderByStartDtDesc 해당 메소드를 사용하기 위해선 ROOT 권한이 있어야 한다.
- 이번엔 컨트롤러에 PostAuthorize를 적용해 보겠다.
@GetMapping("/myLoans")
@PostAuthorize("hasRole(ROOT)")
public List<Loans> getLoanDetails(@RequestParam int id) {
List<Loans> loans = loanRepository.findByCustomerIdOrderByStartDtDesc(id);
if (loans != null ) {
return loans;
}else {
return null;
}
}
- 객체가 반환될 때 엔드유저의 권한을 체크하는 역할을 수행한다.
- 메소드 내부의 로직은 모두 실행이 되지만 객체의 반환은 이뤄지지 않는 것을 확인할 수 있다.
- preFilter는 매개변수의 조건을 확인하는데 쓰인다.
- 그러나 제약조건이 있는데, 오로지 매개변수가 컬렉션일때만 사용가능하다. (List, set, map)
- preFilter("filterObject.contactName != 'Test'")와 같이 컬렉션 객체중 contactName이 Test인 것을 거르는 용도로 사용될 수 있다.
- postFilter는 반환 객체를 확인하는 용도로 사용된다.
- postFilter는 반환 객체의 유형이 컬렉션이어야 한다.
- 만약 총 10개의 node중 2개가 조건에 부합하지 않는다면 8개의 node만 반환될 것이다.
- 고객에게 문의가 들어왔을때 고객의 이름에 test라면 문의를 데이터베이스에 저장하지 않는 로직을 작성해보겠다.
@PostMapping("/contact")
@PreFilter("filterObject.contactName != 'Test'")
public List<Contact> saveContactInquiryDetails(@RequestBody List<Contact> contacts) {
Contact contact = contacts.get(0);
contact.setContactId(getServiceReqNumber());
contact.setCreateDt(new Date(System.currentTimeMillis()));
contact = contactRepository.save(contact);
List<Contact> returnContacts = new ArrayList<>();
returnContacts.add(contact);
return returnContacts;
}
- 다음과 같이 preFilter를 통해 Test 이름을 갖고있는 객체를 거를 수 있다.
- 만약 Test 이름을 가진 node가 List에 포함돼있다면 해당 node만 걸러지고 나머지 node들만이 들어오게된다.
'spring > spring security' 카테고리의 다른 글
스프링 시큐리티 기본 개념공부 11. (Oauth2 실습) (0) | 2024.07.18 |
---|---|
스프링 시큐리티 기본 개념공부 10. (OAUTH2 란?) (1) | 2024.07.18 |
스프링 시큐리티 기본 개념공부 8. (JWT 토큰의 개념과 사용 방법) (1) | 2024.06.16 |
Spring Security 기본 개념 공부 7. (사용자 커스텀 필터 작성 방법) (0) | 2024.06.01 |
Spring Security 기본 개념 공부 6. (권한 부여와 인증 방법) (0) | 2024.05.26 |