익명 인증 사용자에 대해서 알아보고 전체적인 흐름을 확인한다.
스프링 시큐리티에서는 "인증되지 않은 사용자"를 "익명으로 인증된 사용자"로 취급하고 있으며, 이는 액세스 제어 속성을 구성하는데 더 편리하게 하기 위함이다.
SecurityContextHolder
가 항상 Authenticaion
객체를 포함하고 null을 포함하지 않는다는 규칙을 세우게 되면 클래스를 더 견고하게 작성할 수 있다.
즉, 인증 받은 사용자나, 인증 받지 않은 사용자나 둘 다 객체를 생성해서 구분하고 관리하겠다는 의미다.
그리고 인증 받은 사용자는 인증 객체를 SecurityContext
에 저장하고 이를 세션에도 저장했지만, 익명 인증 사용자는 SecurityContext
에 저장하지만 세션에 SecurityContext
를 저장하지 않는다.
익명 사용자 또한 객체로 관리하기 때문에 익명 사용자의 권한을 별도로 설정할 수 있어, 인증 받은 사용자는 접근할 수 없는 리소스를 별도로 구성이 가능하다.
그러니까 보통 인증을 시도하면 요청으로부터 받은 credentials를 가지고 유효한 회원인지 확인하고, 유효하다면 회원 정보를 세션에 저장한다.
그런데 유효한 회원이 아니라면 세션에 회원 정보를 null로 저장하고, 인증받지 못한 회원이구나 판단해도 되지만, spring security에서는 인증 받지 못한 사용자를 위한 클래스도 구성해서 인증을 받은 사용자, 익명 사용자를 둘 다 객체로 구분하고 관리하는 것을 목적으로 한다.
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequest(auth -> auth.anyRequest().authenticated())
.formLogin(Customizer.withDefaults())
.anonymous(anonymous ->
//익명 사용자의 username을 설정한다.
anonymous.principal("guest")
//익명 사용자의 권한을 설정한다.
anonymous.authorities("ROLE_GUEST")
);
return http.build();
}
AnonymousAuthenticationFilter
는 인증 받지 못한 익명 사용자를 처리하는 필터다.
여기서 AnonymousAhtuenticaionToken
을 생성하고 이 토큰 안에 기본적으로 username은 "anonymousUser", role은 "ROLE_ANONYMOUS"로 설정되어있다.
principal메소드로 username을 설정할 수 있고, authorities메소드로 role을 설정할 수 있다.
Authentication
타입으로 선언하면 HttpServletRequest
객체의 getPrincipal
메소드를 사용하여 파라미터를 해결한다.public String method(Authentication authentication) {
//authentication == null
...
}
이 때 authentication 파라미터의 값이 익명 사용자일 경우 null
로 값이 들어오게 된다.
인증된 사용자라면 인증된 사용자 정보를 AuthenticationToken
타입의 객체를 값으로 받게된다.
Authenticaion
객체를 얻기 위해서는 @CurrentSecurityContext
어노테이션을 파라미터에 사용하면 CurrentSecurityContextArgumentResolver
가 동작하여 요청 파라미터를 처리한다.public String method(@CurrentSecurityContext SecurityContext context) {
return context.getAuthentication().getName();
}
AnonymousAuthenticationFilter
는 익명 사용자인 경우를 처리하는 필터다.
인증받지 않은 사용자가 요청할 때 SecurityContext
의 Authentication
객체는 null
이다.
이 경우에 AnonymousAuthenticationFilter
를 만날 때, AnonumousAuthenticationToken
을 생성하고 SecurityContext
에 저장한 후에 이 SecurityContext
를 SecurityContextHolder
에 저장한다.
하지만, AnonymousAuthenticationFilter
는 요청이 이 필터에 도달하기 전에 인증받은 경우라면 아무 동작도 하지 않는다.
익명 사용자인 경우를 처리하는 필터이기 때문이다.
즉, Authentication
이 null인지 아닌지를 체크한 후 동작하는 필터다.
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/anonymous").hasRole("GUEST")
.requestMatchers("/anonymousContext", "/authentication").permitAll() //익명 사용자를 참조하는 방법
.anyRequest().authenticated() //모든 요청은 인증을 받은 상태에서만 가능하도록 설정
)
.formLogin(Customizer.withDefaults())
.anonymous(httpSecurityAnonymousConfigurer -> httpSecurityAnonymousConfigurer
.principal("guest")
.authorities("ROLE_GUEST")
);
return http.build();
}