정수원님의 강의 스프링 시큐리티 완전 정복 [6.x 개정판] 보면서 공부한 내용입니다.
check()
verify()
💡 Method Security를 시작하려면 @Configuration이 있는 곳에 @EnableMethodSecurity를 추가하면 된다.
@EnableMethodSecurity
@Configuration
public class SecurityConfig {
public SecurityFilterChain config(HttpSecurity http) throws Exception{
return http.build();
}
}
http.authorizeHttpRequests(auth -> auth
.requestMatchers("/user").hasRole("USER")
// 시큐리티 내부에서 저장하는 정보
@Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) {
http.authorizeHttpRequests(auth -> auth
.requestMatchers("/user").authenticated()
.requestMatchers("/myPage").fullyAuthenticated()
.requestMatchers("/guest").anonymous()
.requestMatchers("/history").rememberMe());
return http.build();
}
public class CustomAuthorizationManager implements AuthorizationManager<RequestAuthorizationContext> {
private static final String REQUIRED_ROLE = "ROLE_SECURE";
@Override
public AuthorizationDecision check(Supplier<Authentication> authentication, RequestAuthorizationContext object) {
Authentication auth= authentication.get();
if(auth == null || !auth.isAuthenticated() || auth instanceof AnonymousAuthenticationToken){
// 인증 정보 없거나 인증을 받지 못했거나 익명사용자인 경우
return new AuthorizationDecision(false);
}
// 권한 요청 중 하나라도 일치하는지 확인
boolean hasRequireRole = auth.getAuthorities().stream()
.anyMatch(grantedAuthority -> REQUIRED_ROLE.equals(grantedAuthority.getAuthority()));
return new AuthorizationDecision(hasRequireRole);
}
}
// SecurityConfig Class
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/user").hasRole("USER")
.requestMatchers("/db").access(new WebExpressionAuthorizationManager("hasRole('DB')"))
.requestMatchers("/admin").hasAuthority("ROLE_ADMIN")
.requestMatchers("/api").access(new CustomAuthorizationManager())
.anyRequest().authenticated())
.formLogin(Customizer.withDefaults())
.csrf(AbstractHttpConfigurer::disable);
return http.build();
}
💡 요청 기반은 필터에서 여러가지 빈 또는 클래스를 만들어 초기화 설정을 이룬다
public List<User> user()
UserService
빈의 대리자 즉, 가짜 객체를 생성MethodInterceptor
Advice 등록UserService
의 프록시 객체가 참조된다💡 Advice
- 프록시가 호출하는 부가 기능으로 프록시 로직이라고 생각하면 된다
@PreAuthorize, @Secured, @PermitAll
에 설정된 권한을 평가하는 클래스@PostAuthorize
에 설정된 권한을 평가하는 클래스@PreFilter
어노테이션에서 표현식을 평가하여 메소드 인자를 필터링 하는 구현체@PostFilter
어노테이션에서 표현식을 평가하여 보안 메서드에서 반환된 객체를 필터링 하는 구현체@EnableMethodSecurity(prePostEnabled = false)
@Configuration
public class MethodSecurityConfig {
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public Advisor preAuthorize() { // 메소드 진입 전 권한 심사하는 클래스
return AuthorizationManagerBeforeMethodInterceptor.preAuthorize(new MyPreAuthorizationManager());
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public Advisor postAuthorize() { // 메소드 진입 후 권한 심사하는 클래스
return AuthorizationManagerAfterMethodInterceptor.postAuthorize(new MyPostAuthorizationManager());
}
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public Advisor protectServicePointcut() {
AspectJExpressionPointcut pattern = new AspectJExpressionPointcut();
pattern.setExpression("execution(* io.security.MyService.user(..))"); // 권한 규칙이 실행되어야되는 메서드 설정
// 반환 타입 상관없이 io.security안에 있는 MyService클래스의 user메서드를 호출할 때 권한 규칙을 작동해라
// 해당 설정을 통해 스프링 초기화가 실행됨
manager = AuthorityAuthorizationManager.hasRole("USER");
// 권한 규칙을 실행하는 매니저
// 권한 = user
return new AuthorizationManagerBeforeMethodInterceptor(pattern, manager);
// 메서드 호출 진입 전 interceptor가 작동
}
💡 Joinpoint
- 클래스나 필드 또는 메서드에 어드바이스를 적용할 수 있는 대상 자체를 의미한다
- Spring AOP에서 Joinpoint는 항상 메서드의 실행을 의미한다. 즉, 메서드 레벨 중에 AOP 적용할 수 있는 지점으로 Aspect Code 추가하면 공통기능이 해당 지점 전/후에 자동으로 추가되어 실행이 된다.
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public MethodInterceptor methodInterceptor() {
// 현재 메서드를 호출한 사용자의 인증 상태만 보겠다
AuthorizationManager<MethodInvocation> authorizationManager = new AuthenticatedAuthorizationManager<>();
// CustomMethodInterceptor에 생성자로 전달
return new CustomMethodInterceptor(authorizationManager);
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public Pointcut pointcut() {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
// 어떤 메소드에 권한 규칙을 설정할 것 인가
pointcut.setExpression("execution(* io.security.springsecuritymaster.chapter9.DataService.*(..))");
return pointcut;
}
@Bean
public Advisor serviceAdvisor(){
return new DefaultPointcutAdvisor(pointcut(),methodInterceptor());
}