[프로젝트] 시큐리티 권한 체크 `@PreAuthorize 또는 @Secured`

Spring Security 5.7.11 기준이다.

  • 스프링 시큐리티에는 컨트롤러에 역할(Role) 기반 접근 제한을 설정하는 방법에 여러 가지가 있는데,
    • 가장 일반적인 방법으로는 @PreAuthorize 또는 @Secured 어노테이션을 사용하는 것이다.
    • 해당 어노테이션은 메서드 수준의 보안이 가능하다.

@PreAuthorize

  • 특정 역할을 가진 사용 역할을 가진 사용자만 메서드를 호출할 수 있도록 제한할 수 있다.
    @Controller
    public class SomeController {
    
        @PreAuthorize("hasRole('ROLE_ADMIN')")
        @RequestMapping("/adminOnly")
        public String adminOnly() {
            // 관리자만 접근 가능한 로직
            return "admin";
        }
    }
    @PreAuthorize("hasAnyRole('ROLE_CUSTOMER', 'ROLE_ADMIN')")
    	//OR 조건으로 역할을 제한
    	@GetMapping("/{orderId}")
    	public ResponseEntity<OrderResponseDTO> getOrder(@PathVariable Long orderId) {
    		OrderRequestDTO orderRequestDTO = OrderRequestDTO.forActiveOrder(orderId);
    		return ResponseEntity.ok(orderService.getOrder(orderRequestDTO));
    	}

    어노테이션 소스

    package org.springframework.security.access.prepost;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Inherited;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     * Annotation for specifying a method access-control expression which will be evaluated to
     * decide whether a method invocation is allowed or not.
     *
     * @author Luke Taylor
     * @since 3.0
     */
    @Target({ ElementType.METHOD, ElementType.TYPE })
    @Retention(RetentionPolicy.RUNTIME)
    @Inherited
    @Documented
    public @interface PreAuthorize {
    
    	/**
    	 * @return the Spring-EL expression to be evaluated before invoking the protected
    	 * method
    	 */
    	String value();
    
    }
    • 타입
      • 메서드와 타입(클래스, 인터페이스 등) 에 적용가능한 어노테이션입니다.
      • 클래스 전체 또는 인터페이스
    • Retention
      • 어노테이션의 정보가 런타임시에도 유지되어야함.
      • JVM이 클래스를 메모리에 로드하는 경우, 어노테이션의 정보가 런타임시에도 유지가 되어야 해당 권한에 따른 접근이 가능할 것이다
    • Inherited
      • 상속된 클래스가 부모 클래스의 PreAuthorize 어노테이션을 상속받을 수 있음.
      • 해당 어노테이션이 부모 클래스에 적용된다면, 이를 상속받는 자식 클래스도 같은 보안 정책을 적용받게 되는 것입니다
    • Documented
      • javadoc 과 같은 문서에 포함 가능 ㅇㅇ

    • 어노테이션 내부의 value 메서드는 Spring Expression Language(SpEL) 표현식을 반환함.
    • 메서드 호출 전에 평가되고, 표현식의 결과에 따라 메서드 호출 허용, 거부 결정

@PostAuthorize

  • PreAuthorize 와 거의 동일하다.
  • 하지만, 권한 검사 이후 → 메서드 실행 → 그 이후의 권한을 검사할 필요가 있는 경우 해당 어노테이션을 사용한다.
    • 예를 들어
      • 사용자가 자신의 프로필 정보를 요청
        • 해당 메서드가 사용자 정보를 반환시
        • @PostAuthorize 를 사용하여
        • 반환된 사용자 정보가 요청한 사용자의 정보와 일치하는지를 확인이 가능하다.
    @PostAuthorize("returnObject.email == authentication.email") // 리턴 객체의 이메일과 인증정보의 이메일 등을 비교가 가능함

@Secured

  • SpEL 을 사용하지 않고, 단순히 역할을 문자로로만 사용한다.
    import org.springframework.security.access.annotation.Secured;
    
    @Controller
    public class SomeController {
    
        @Secured("ROLE_ADMIN")
        @RequestMapping("/adminOnly")
        public String adminOnly() {
            // 관리자만 접근 가능한 로직
            return "admin";
        }
    }
    • 소스
    /**
     * Java 5 annotation for describing service layer security attributes.
     *
     * <p>
     * The <code>Secured</code> annotation is used to define a list of security configuration
     * attributes for business methods. This annotation can be used as a Java 5 alternative to
     * XML configuration.
     * <p>
     * For example:
     *
     * <pre>
     * &#064;Secured({ &quot;ROLE_USER&quot; })
     * public void create(Contact contact);
     *
     * &#064;Secured({ &quot;ROLE_USER&quot;, &quot;ROLE_ADMIN&quot; })
     * public void update(Contact contact);
     *
     * &#064;Secured({ &quot;ROLE_ADMIN&quot; })
     * public void delete(Contact contact);
     * </pre>
     * @author Mark St.Godard
     */
    @Target({ ElementType.METHOD, ElementType.TYPE })
    @Retention(RetentionPolicy.RUNTIME)
    @Inherited
    @Documented
    public @interface Secured {
    
    	/**
    	 * Returns the list of security configuration attributes (e.g.&nbsp;ROLE_USER,
    	 * ROLE_ADMIN).
    	 * @return String[] The secure method attributes
    	 */
    	String[] value();
    
    }
    • PreAuthorize 와 거의 동일하지만, SpEL 을 사용할 수 없기에, 별도 권한에 대한 조건을 걸기는 힘들다.
    • 사실상 PreAuthrize 가 조금 더 실용적인 것 같다.

공식문서

Method Security :: Spring Security
This version is still in development and is not considered stable yet. For the latest stable version, please use Spring Security 6.2.1!
https://docs.spring.io/spring-security/reference/5.7-SNAPSHOT/servlet/authorization/method-security.html#_customizing_authorization


Uploaded by N2T