본문 바로가기

Spring Boot/Security 쿠키,세션 기반 인증,인가

세션 기반 사용자 인가 구현 : 메서드 보안을 통한 인가

 - 메서드 보안을 통한 인가(Authorization)의 개념

 - @EnableMethodSecurity 를 활용하여 메서드 수준에서 보안 활성화하기

 - @PreAuthorize, @PostAuthorize 애너테이션 사용법

 - 메서드 파라미터를 활용한 동적 인가

 - SpEL 을 이용해서 유연한 접근 제어하기


메서드 보안 개요

URL 기반 인가는 요청 경로에 따라 접근을 제어하지만, 메서드 보안은 실제 서비스 계층이나 비즈니스 로직의 메서드 실행 여부를 제어한다

이러한 방식은 컨트롤러, 서비스 메서드 단위에서 더욱 정밀한 접근 제어를 가능하게 한다

사용자 요청에 따라 컨트롤러의 메서드에서 인가 검사를 한다


@EnableMethodSecurity 설정하기

메서드 보안을 활성화하려면, Spring Security 설정 클래스에서 @EnableMethodSecurity 를 선언하면 된다

@Configuration
@EnableMethodSecurity(prePostEnabled = true)
public class SecurityConfig {
	// URL 기반 설정과 병행할 수 있다
}

 

  • prePostEnabled = true 옵션을 활성화해야 @PreAuthorize 와 @PostAuthorize 애너테이션을 사용할 수 있다
  • 메서드 보안은 URL 인가보다 우선 적용되며, 더욱 세밀한 제어를 제공한다

 

항목 설명
@EnableMethodSecurity 메서드 보안을 활성화하는 애너테이션
prePostEnabled @PreAuthorize, @PostAuthorize 애너테이션 사용여부

 


@PreAuthorize, @PostAuthorize 애너테이션

1. @PreAuthorize

메서드 실행 전에 접근 권한을 검사한다

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;

@Service
public class ReportService {
    // 메서드 실행 전에 접근 권한을 확인한다
    @PreAuthorize("hasRole('ADMIN')")
    public String generateAdminReport() {
        return "Admin Report";
    }

    @PreAuthorize("hasAnyRole('USER','ADMIN')")
    public String generateUserReport() {
        return "User Report";
    }
}

 

  • hasRole('ADMIN') : 관리자 권한이 있어야 실행 가능
  • hasAnyRole('USER', 'ADMIN') : 일반 사용자 또는 관리자 권한이 있어야 실행 가능

 

 

2. @PostAuthorize

메서드를 일단 실행하고, 반환값을 기준으로 접근을 제어한다

import com.b1uffer.multisessiontest.entity.Document;
import com.b1uffer.multisessiontest.repository.DocumentRepository;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.stereotype.Service;

@Service
public class DocumentService {
    private final DocumentRepository documentRepository;

    DocumentService(DocumentRepository documentRepository) {
        this.documentRepository = documentRepository;
    }

    // 문서를 조회한 후 반환한다
    @PostAuthorize("returnObject.owner == authentication.name")
    public Document getDocument(Long id) {
        return documentRepository.findById(id).orElseThrow(() -> new IllegalArgumentException("Document not found"));
    }
}

 

반환된 객체의 owner 필드(returnObject.owner)가
현재 로그인한 사용자의 이름(authentication.name)과 일치해야 접근이 허용된다

 

 

  • @PreAuthorize 는 메서드 실행 전 제어, @PostAuthorize 는 실행 후 반환값 기반 제어이다
  • @PostAuthorize 는 결과에 따라 접근을 제어할 때 유용하다

메서드 파라미터 기반 동적 인가

메서드 인자로 전달된 값(매개변수)에 따라 접근을 제어할 수 있다

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;

@Service
public class UserProfileService {

    @PreAuthorize("#username == authentication.name")
    public String getUserProfile(String username) {
        return "userProfile : " + username;
    }
}

 

  • #username : 메서드 파라미터 참조
  • authentication.name : 현재 로그인한 사용자의 이름
  • 두 값이 같을때만 접근을 허용함

 

  • 파라미터 기반 인자는 "자기 자신만 조회 가능" 과 같은 제약을 구현할 때 유용하다
  • 보통 사용자 ID나 이메일 기반 접근 제어에 많이 활용된다
@PreAuthorize 설명
#파라미터명 메서드 인자 참조
authentication.name 현재 로그인한 사용자의 이름

SpEL(Spring Expression Language) 활용하기

Security 에서는 SpEL을 활용해서 매우 유연한 인가 조건을 정의할 수 있다

 

1. 예제

    @PreAuthorize("hasRole('ADMIN') and #id == authentication.principal.id")
    public String editUser(Long id) {
        return "edit User : " + id;
    }

 

  • hasRole('ADMIN') : 관리자 권한이 있을때에만 이 메서드를 실행할 수 있음
  • #id == authentication.principal.id : 파라미터로 받은 id가 로그인 사용자 id와 동일해야 허용함

 

 

2. SpEL 주요 키워드

키워드 설명
authentication 현재 인증 객체
principal 현재 사용자의 객체(UserDetails)
authorities 권한 목록
#파라미터명 메서드의 인자 참조
returnObject 반환 객체, @PostAuthorize 에서 사용함

 

 

  • SpEL을 통해 단순 권한 체크 이상의 비즈니스 로직 기반 접근 제어가 가능하다
  • 지나치게 복잡한 표현식은 코드 가독성을 낮춘다. 커스텀 권한 체크 메서드로 분리하는게 좋다고 함