오늘은 인가처리 Annotation에 대해서 알아볼 것 입니다.
이 어노테이션을 사용한다면 복잡한 코드가 간결하고 깔끔하게 완성가능합니다.
1. SecurityConfig파일에
@EnableMethodSecurity(securedEnabled = true, prePostEnabled = true)
작성해주어야 사용가능합니다.
이렇게 작성하여야 @Secured, @PreAuthorize, @PostAuthorize 활성화가 됩니다.
<표현가능한 표현식>
- hasRole([role]) : 현재 사용자의 권한이 파라미터의 권한과 동일한 경우 true
- hasAnyRole([role1,role2]) : 현재 사용자의 권한이 파라미터의 권한 중 일치하는 것이 있는 경우 true
- principal : 사용자를 증명하는 주요객체(User)를 직접 접근할 수 있다.
- authentication : SecurityContext에 있는 authentication 객체에 접근 할 수 있다.
- permitAll : 모든 접근 허용
- denyAll : 모든 접근 비허용
- isAnonymous() : 현재 사용자가 익명(비로그인)인 상태인 경우 true
- isRememberMe() : 현재 사용자가 RememberMe 사용자라면 true
- isAuthenticated() : 현재 사용자가 익명이 아니라면 (로그인 상태라면) true
- isFullyAuthenticated() : 현재 사용자가 익명이거나 RememberMe 사용자가 아니라면 true
사용예시
이렇게 @PreAuthorize는 표현식이 가능하며, @Secured는 표현식이 불가합니다.
간단한 인가처리에는 @Secured를, 복잡한 인가처리는 @Post/PreAuthorize를 사용합니다.
@PostMapping("/notice")
@PreAuthorize("hasRole('ROLE_MANAGER') or hasRole('ROLE_OWNER')")
public ResponseEntity<NoticeResponseDto> createNotice(@RequestBody NoticeRequestDto noticeRequestDto) {
NoticeResponseDto responseDto = noticeService.createNotice(noticeRequestDto);
return ResponseEntity.status(HttpStatus.CREATED).body(responseDto);
}
공지사항 작성 시, 예를 들어 관리자인 ROLE_MANAGER나 가게 주인인 ROLE_OWNER만 작성할 수 있도록 제한하고 싶다고 가정해봅시다. 이 경우 @PreAuthorize를 사용하여 이러한 역할을 가진 사용자만 메서드에 접근할 수 있도록 설정할 수 있습니다.
1. #을 사용한 값 비교 예시
@PostMapping("/notice")
@PreAuthorize("#noticeRequestDto.name == principal.username or hasRole('ROLE_MANAGER')")
public ResponseEntity<NoticeResponseDto> createNotice(@RequestBody NoticeRequestDto noticeRequestDto) {
NoticeResponseDto responseDto = noticeService.createNotice(noticeRequestDto);
return ResponseEntity.status(HttpStatus.CREATED).body(responseDto);
}
이제 #을 사용하여 더 구체적인 제어를 할 수 있는 방법을 살펴보겠습니다. 예를 들어, 공지사항을 작성할 때 현재 로그인한 사용자의 이름이 공지사항 요청에 포함된 작성자 이름과 일치하는지 확인하고 싶다면, 다음과 같이 설정할 수 있습니다.
이 경우 #noticeRequestDto.Name은 메서드에 전달된 NoticeRequestDto 객체의 name 필드를 의미합니다. principal.username은 현재 로그인한 사용자의 이름입니다. 이 조건은 작성자가 자신의 이름으로 공지사항을 작성하거나 관리자인 경우에만 공지사항을 작성할 수 있도록 제한합니다.
@PreAuthorize("#noticeRequestDto.name == principal.username or hasRole('ROLE_MANAGER')")
@PreAuthorize 표현식에서 #noticeRequestDto.name과 같이 사용되는 name은 실제 클래스의 필드 이름과 일치해야 합니다.
필드 이름은 대소문자를 구분하므로, NoticeRequestDto 클래스의 필드가 name으로 선언되어 있다면, #noticeRequestDto.name이라고 정확하게 써야 합니다.
예를들어
public class NoticeRequestDto {
private String name;
// getters and setters
}
NoticeRequestDto클래스의 필드가 name으로 선언되어있다면 #NoticeReqestDto.name이라고 정확하게 입력해야합니다.
2. principal.username의 의미
principal.username 은 현재 인증된 사용자의 username을 나타냅니다.
이 값은 보통 UserDetails 인터페이스를 구현한 클래스, User엔티티에서 가져옵니다.
Spring Security의 기본 설정에서는 username이라는 필드를 사용하여 사용자를 구분합니다.
public class User implements UserDetails {
private String username;
private String password;
// other fields, getters, setters, and methods
}
만약 User엔티티에 username 이라는 필드가 다음과 같이 정의되어 있다면, principal.username 은 현재 로그인한 사용자의 username의 필드값을 참조하게됩니다.
'개발관련' 카테고리의 다른 글
JPA) JPA Auditing 사용하기 (1) | 2024.09.05 |
---|---|
[Spring Security] canAccessUser 메서드 (0) | 2024.09.04 |
CI/CD 란 무엇인가 ? (0) | 2024.08.19 |
Docker 명령어에 대해서 알아보자. (0) | 2024.08.14 |
Docker 란 무엇일까 ? (0) | 2024.08.13 |