Spring Security AuthenticationEntryPoint(인증), AccessDeniedHandler(인가)
Spring Security 에서 인증 및 인가 등 사용자의 권한을 처리하게 된다.
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable())
.addFilterAt(beforeFilter(), UsernamePasswordAuthenticationFilter.class)
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/auth/**").permitAll()
.requestMatchers("/test/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
....생략
.exceptionHandling(exception -> exception
.accessDeniedHandler(accessDeniedHandler())
.authenticationEntryPoint(entryPoint())
);
return http.build();
}
@Bean
public AuthenticationAccessDeniedHandler accessDeniedHandler() {
return new AuthenticationAccessDeniedHandler();
}
@Bean
public AuthenticationEntryPointHandler entryPoint() {
return new AuthenticationEntryPointHandler();
}
위 내용은 Spring Security 6 버전의 설정 내용이다.
.exceptionHandling 설정을 통해 인증 및 인가에 대해 처리할 수 있다.
AuthenticationEntryPoint(인증)
인증이 되지 않은 사용자가 인증이 필요한 엔드포인트 즉 인증을 하고나서 접근할 수 있는 페이지로
접근했을 때 처리하기 위한 인증 핸들러이다.
Spring Security 기본 설정으로는 HttpStatus 401과 함께 기본 오류페이지를 보여준다.
기본 오류페이지가 아닌 커스텀 페이지와 HttpStatus 401 에러에 대해 특정 로직을 수행해야 한다면
AuthenticationEntryPoint 인터페이스를 직접 구현하여 Spring Security 에 설정하면 된다.
import java.io.IOException;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
public class AuthenticationEntryPointHandler implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException, ServletException {
response.setStatus(HttpStatus.UNAUTHORIZED.value());
response.setCharacterEncoding("UTF-8");
}
}
위처럼 상태값을 401 로 설정하여 에러를 발생시킨다.
커스텀 페이지를 사용하려면 response 의 sendRedirect 를 통해 커스텀 에러 페이지로 이동시킨다.
AccessDeniedHandler(인가)
인증된 사용자가 권한이 없는 페이지를 접근했을 때 403 Forbidden 에러가 발생한다.
기본 오류페이지가 존재하며 커스텀 페이지도 만들 수 있다.
HttpStatus 403 Forbidden 에러는 사용자의 권한이 부족하여 요청이 거부된 상태를 말한다.
커스텀 페이지를 만들기 위해선 AccessDeniedHandler 인터페이스를 구현하여 Spring Security 에 설정하면 된다.
본인은 보여주기 위한 페이지만 간단하게 만들었다.
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/auth/**").permitAll()
.requestMatchers("/test/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
...생략
.exceptionHandling(exception -> exception
.accessDeniedHandler(accessDeniedHandler())
.authenticationEntryPoint(entryPoint())
);
return http.build();
}
import java.io.IOException;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
public class AuthenticationAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response,
AccessDeniedException accessDeniedException) throws IOException, ServletException {
response.sendRedirect(request.getContextPath() + "/auth/accessDenied");
}
}
설정은 위 Spring Security .exceptionHandling 으로 설정한다.
위 내용중 로그인이 완료되어 "/test" 라는 URL 로 요청했지만 아래와 같이 접근할 수 없는 AccessDenied(403 Forbidden)
에러가 발생했다.
이유는 "/test/**" 의 접근 권한은 "ROLE_ADMIN" 의 권한을 가지고 있기 때문에 ADMIN 권한을 가지지 않은 계정이
접근했을 땐 AccessDenied 에러가 발생한다.
본인은 Spring Security UserDetails 에 아래와 같이 설정했다.
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
authorities.add(new SimpleGrantedAuthority("ROLE_"+userInfo.getUser_role()));
DB에 저장된 role 값을 권한으로 설정했고 아래는 2개의 테스트 계정이 있다.
admin 계정은 role 권한이 ADMIN 이므로 접근할 수 있으며, user 계정은 위 이미지와 같이
403 Forbidden 에러가 발생했다.