본문 바로가기
개발관련

[Spring Security] @Secured, @PreAuthorize, @PostAuthorize

by 수바니 2024. 9. 4.

 

오늘은 인가처리 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