본문 바로가기

STUDY/Spring

Spring Boot | Spring Security @PreAuthorize사용하기

의존성 참고!

// Sprint Security
implementation 'org.springframework.boot:spring-boot-starter-security'
// OAuth2
implementation group: 'org.springframework.security.oauth', name: 'spring-security-oauth2', version: '2.3.5.RELEASE'
// JWT
implementation group: 'org.springframework.security', name: 'spring-security-jwt', version: '1.1.1.RELEASE'

 

1. @EnableGlobalMethodSecurity 설정

MethodSecurity는 말그대로 메소드 수준에서 권한을 제어할 수 있도록 해준다!
특정 메소드마다 실행할 수 있는 역할을 제한할 수 있도록 해줌.
단순히 허용, 거부 하는 것 보다 더 복잡한 규칙을 적용할 수 있음.

GlobalMethodSecurity 사용을 활성화 하는 @EnableGlobalMethodSecurity 어노테이션을 추가

  • prePostEnabled - Spring Security의 @PreAuthorize, @PreFilter /@PostAuthorize, @PostFilter어노테이션 활성화 여부
  • securedEnabled - @Secured어노테이션 활성화 여부
  • jsr250Enabled - @RoleAllowed 어노테이션 사용 활성화 여부 
@Configuration
@EnableGlobalMethodSecurity(
  prePostEnabled = true, 
  securedEnabled = true, 
  jsr250Enabled = true)
public class MethodSecurityConfig 
  extends GlobalMethodSecurityConfiguration {
}

 

실제로는 아래와 같이 설정해주었다. prePostEnabled만 true로 활성화

OAuth2MethodSecurityExpressionHandler()는.. OAuth2를 사용한다면 해주어야 함..!

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {

    @Override
    protected MethodSecurityExpressionHandler createExpressionHandler() {
        return new OAuth2MethodSecurityExpressionHandler();
    }
}

 

2. @PreAuthorize 사용!

@PreAuthorize는 해당 메서드가 호출되기 이전에 검사한다. 실제로 해당 메서드를 호출할 권한이 있는지를 확인!

(PostAuthorize는 메서드 호출 이후)

 

주석처리된 코드에서도 알 수 있듯.. 원래는 endpoint마다 저 코드를 복붙하여 username이라는 PathVariable을 검사하고...

관리자 권한(ROLE_ADMIN)이 없는데 본인 id(username)이 아닌 남의 id를 입력하면 관리자 권한이 없다는 예외처리를 해줬었는데

이제 @PreAuthorize로 간단히 처리할 수 있게 되었다!

    @ApiOperation(value = "get user info", notes = "유저 정보 조회 me 혹은 유저 id로 조회 가능")
    @GetMapping(value = "/{username}", produces = "application/json")
    @PreAuthorize("#username == 'me' or #username == authentication.name or hasRole('ROLE_ADMIN')")
    public ResponseEntity<?> getUserInfo(Authentication authentication,
                            @ApiParam(value = "username 혹은 me", required = true)
                            @PathVariable(name = "username") String username)  {

//        if(username.equals("me") || username.equals(authentication.getName()) ||
//                authentication.getAuthorities().contains(new SimpleGrantedAuthority("ROLE_ADMIN"))) {
//            return ResponseEntity.ok().body(userService.findByName(username.equals("me") ? authentication.getName() : username));
//        }else {
//            throw new AccessDeniedException("관리자 권한이 필요합니다.");
//        }


        return ResponseEntity.ok().body(userService.findByName(username.equals("me") ? authentication.getName() : username));
    }

 

* returnObject를 이용해 반환값에 접근할 수도 있다.

@PreAuthorize("returnObject.name == #username")

 

3. 더 간단히.. Method로 권한여부 체크하기!

webSecurity라는 Bean/Component에 정의된 public boolean 메서드를 이용해 권한 여부를 체크할 수 있다.

@PreAuthorize("@webSecurity.checkAuthority(authentication,#username)")

 

메서드 안에 권한 여부를 체크하는 코드를 작성하고..

@Component("webSecurity")
public class WebSecurity {

    public boolean checkAuthority(Authentication authentication, String userid) {
        if(authentication.getAuthorities().contains(new SimpleGrantedAuthority("ROLE_ADMIN"))
                || userid.equals("me") || userid.equals(authentication.getName()) ) {
            return true;
        }else {
            return false;
        }

    }
}

 

실행 했는데 org.springframework.expression.spel.SpelEvaluationException가 발생하면!

MethodSecurityConfig를 수정해 ApplicationContext를 등록해준다.

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {

    @Autowired
    private ApplicationContext applicationContext;

    @Override
    protected MethodSecurityExpressionHandler createExpressionHandler() {
        OAuth2MethodSecurityExpressionHandler oAuth2MethodSecurityExpressionHandler =
                new OAuth2MethodSecurityExpressionHandler();
        oAuth2MethodSecurityExpressionHandler.setApplicationContext(applicationContext);
        return oAuth2MethodSecurityExpressionHandler;
    }

}

 

+) @PreAutorized를 컨트롤러 자체에 적용할 수도 있다!

모든 endpoints에서 @PreAuthorize가 적용된 효과를 볼 수 있음

@PreAuthorize("@methodSecurity.checkAuthority(authentication,#username)")
public class UserController {

	/* ... 생략 ... */

}

+) 참고

 

Introduction to Spring Method Security | Baeldung

A guide to method-level security using the Spring Security framework.

www.baeldung.com