Spring Security의 이해
- Spring Security
- Spring
Spring Security의 기본제공 API와 Filter를 이해해보자.
Spring Security의 기능
- 💡모든 Request는 인증이 되어야 자원의 접근이 가능하다.
- 💡개발자가 따로 구현을 안해도 기본적으로 웹 보안 기능이 작동함.
- Spring Security의 기본 계정, 로그인 페이지를 제공(변경 가능).
- 💡인증방식은 Form 로그인, httpBasic 로그인 방식 제공.
- 💡Server가 기동되면 Spring Security의 초기화 작업, 보안 설정이 진행됨.
사용자 정의(개발자 정의) Security 기능 구현하기

SecurityConfig: 사용자 정의 보안 설정 클래스
WebSecurityConfigurerAdapter: Spring Security의 웹 보안 기능 초기화 및 설정 클래스HttpSecurity: 세부적인 보안 기능 설정 API
인증 API: http.formLogin(), http.logout() 등등..
인가 API: http.hasRole(), http.antMatchers() 등등..
💡WebSecurityConfigurerAdapter은 더 이상 지원하지 않아 SecurityFilterChain을 Bean으로 등록하여 사용해야한다.
사용자 정의 기능 구현하기
@EnableWebSecurity // 개발자가 Spring Security의 기능을 정의하게 해주는 어노테이션
@RequiredArgsConstructor
@ConditionalOnDefaultWebSecurity
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
public class SecurityConfiguration{
/*
공식 문서와 상이한 이유는 SpringBoot에서 이미 default로 SecurityFilterChain을
등록하는데, @Bean객체로 다시 DI를 시도한다면 둘 중 하나만 선택하라는 오류가 발생한다.
따라서 아래와 같이 2개의 annotation을 클래스에 추가하고 Bean으로 사용하고자 하는 함수에 SecurityFilterChain 함수 위에 @Order을 추가하면 된다.
*/
@Bean
@Order(SecurityProperties.BASIC_AUTH_ORDER)
public void SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/resources/**","/login-page","/register-page","/login-fail").permitAll()
.antMatchers("loginAction").hasRole("USER")
.antMatchers("loginAction").hasRole("ADMIN")
.and()
.formLogin()
.loginPage("/login-page")
.loginProcessingUrl("/login-action")
.successHandler(new LoginSuccessHandler())
.failureUrl("/login-fail")
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/login-page")
.and()
.csrf().disable();
return http.build();
}
}
! Security 설정
HttpSecurity에 사용되는 API들은 docs.spring.io에서 확인할 수 있다. (공식 가이드북)
왜 이렇게 어려워..
Login 인증 처리 프로세스 (Client <-> Server)

과정
- 사용자가 request를 GET 방식으로 /home에 접근시도
- 인증이 안되었다면 로그인 페이지로 리다이렉트
- 사용자가 POST 방식으로
username,password을 넘겨 인증 시도 - Server는 Spring Security가 해당 사용자의
Session을 생성하고, 해당 세션에Authorization 객체를 생성하여SecurityContext에 저장. - 인증을 받은 사용자가 /home에 접근을 시도할 시 Spring Security는 사용자가 가진
Session으로부터Token의 존재 여부를 판단 후, 자원에 접근시킨다. - 이후 Spring Security는
Session에 저장된Token이 있다면 사용자가 인증된 사용자라고 판단하여 인증을 유지한다.
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin()
.loginPage("/login") // 해당 url을 로그인 페이지로 지정
.defaultSuccessUrl("/index") // 로그인 성공 시 해당 url로 리다이렉트
.failureUrl("/login") // 로그인 실패 시 해당 url로 리다이렉트 (기본적으로 ?error=true를 파라미터로 보냄)
.usernameParameter("username") // 사용자 ID 파라미터 지정
.passwordParameter("password") // 사용자 Password 파라미터 지정
.loginProcessingUrl("/login") // 사용자 ID와 password를 제출할 url
.successHandler() // 로그인 성공 후 핸들러 지정 (정의 가능)
.failureHandler() // 로그인 실패 후 핸들러 지정 (정의 가능)
}
UsernamePasswordAuthenticationFilter란?
사용자의 인증(로그인)을과 처리를 담당하는 필터

해당 필터는 Spring에서 만들어놓은 구현체이다. 해당 필터를 재사용해서 jwt와 같은 사례에 적용을 할 수 있다.
- 해당 필터는 자신이 처리할 URL에 요청이 들어오면, 기본적으로 다음 필터로 동작을 넘기지 않고 잡아놓는다.
- 해당 필터는 다음 필터로 동작을 넘겨도, Context가 생성되지 않은 상태에서 넘기기에 인증 후 정보를 활용할 수 없다.
- 해당 필터를 대체할 필터를 만들게 된다면 성공과 실패에 따른 로직을 필수적으로 구현해야한다.
- 만약, 로그인이 완료되었을 때
jwt를 반환하고 싶다면, successHandler를 구현하자.
UsernamePasswordAuthenticationFilter는, Spring Security에서 기본적인(Basic)로그인 폼을 지원하기 위해 미리 구현된 필터이다. Spring Security 설정에서
http.formLogin()을 사용하게 된다면 UsernamePasswordAuthenticationFilter가 등록된다.
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin() // UsernamePasswordAuthenticationFilter 등록
}
LogoutFilter란?
로그아웃 처리를 담당하는 필터

해당 필터는 사용자의 로그아웃 처리를 담당하는 필터이다.
- 사용자가
POST로 로그아웃을 요청한다. (💡Spring Security의 로그아웃은 무조건 POST로 처리해야한다) - AntPathRequestMatcher가 해당 로그아웃 요청을 확인한다.
- 인증 정보가 일치하면 인증 객체를 담고있는 SecurityContext를 Authentication을 사용하여 꺼낸다.
- SecurityContextLogoutHandler가 세션 무효화, 쿠키 삭제, 인증 객체 NULL, SecurityContext에서 정보를 삭제한다.
- 로그아웃이 성공하면 LogoutSuccessHandler를 호출한다.
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.logout() // 로그아웃 처리를 시작한다.
.logoutUrl("/logout") // 로그아웃을 처리하는 URL 지정
.logoutSuccessUrl("/login") //로그아웃 성공 시 URL 지정
.deleteCookies("JSESSIONID","Remember-Me") // 로그아웃 시 해당 쿠키 삭제
.addLogoutHandler(logoutHandler()) // 로그아웃 핸들러 구현
.logoutSuccessHandler(logoutSuccessHandler()) // 로그아웃 성공 후 핸들러 구현
}
Remember Me 사용
Remember Me
: 세션이 만료되거나 클라이언트가 종료되도 Application이 해당 사용자를 기억하는 기능을 말한다.
Remember-Me 쿠키에 대한 http 요청을 확인한 후 토큰 기반 인증을 사용하여 토큰의 유효성을 검사한 뒤, 검증되면 사용자는 로그인이 된다.
💡 중요 :JSEESIONID가 없더라도 Spring Security에Remember-Me쿠키가 존재한다면, 다시 인증을 시도하여JSSSIONID를 재생성한다.
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.rememberMe() // rememberMe 지정
.rememberMeParameter("remember") // RememberMe의 기본 파라미터는 "Remember-Me"이다.
.rememberMeCookieName("remember") // RememberMe의 쿠키 이름을 설정한다.
.tokenValiditySeconds(3600) // 토큰 유효 시간을 설정하며 기본 값은 14일이다.
.alwaysRemember(true) // Remember
.userDetailsService(userDetailsService) // UserDetailsService의 객체를 불러온다.
}
너무 어렵다.