유튜브 "개발자 유미"님 강의를 듣고 정리한 내용입니다.
개인 프로젝트를 만들 때 로그인과 관련된 기능들이 부실하다고 느꼈다. 쿠키와 세션을 사용하여 특정 페이지에 대한 접근과 관련해 제한을 두기도 했지만, 어딘가 부실하다는 느낌을 받았다. 또한 로그인 후에 원래 보던 페이지로 돌아가기 위한 기능을 개발하려고 했을 때 스프링 시큐리티 없이는 불가능하다고 생각했다.
스프링 시큐리티는 인증, 권한 관리 그리고 데이터 보호 기능을 포함하여 웹 개발 과정에서 필수적인 사용자 관리 기능을 구현하는데 도움을 주는 스프링의 프레임워크이다.
스프링 프레임워크를 사용하며 자원 관리를 쉽게 할 수 있었고, 스프링 데이터 JPA를 사용하여 반복되는 코드를 짜는 작업을 줄이고 효율적으로 개발을 할 수 있었다. 이렇듯 스프링을 사용하면서 편리함을 느꼈었는데 보안과 관련해서도 스프링 시큐리티를 사용하면 편의를 제공받을 수 있을 것이다. 사용하지 않을 이유가 없다고 느꼈다.
그래서 스프링 시큐리티 공부를 하려던 찰나에 유튜브에서 개발자 유미님의 좋은 강의를 발견했고, 다음은 그 강의를 들으며 정리한 내용이다.
스프링 시큐리티를 사용하기 위해서 먼저 build.gradle 의 dependencies에 다음을 추가해야 한다.
implementation 'org.springframework.boot:spring-boot-starter-security'
testImplementation 'org.springframework.security:spring-security-test'
Configuration을 작성하지 않으면 모든 요청에 시큐리티가 적용되어 다음과 같이 로그인 폼을 띄운다.

username은 user로, password는 콘솔에서 generated password를 확인하여 로그인을 하면 된다. password는 애플리케이션 실행 시마다 다르게 생성된다.

@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((auth) -> auth
.requestMatchers("/", "/login").permitAll()
.requestMatchers("/admin").hasRole("ADMIN")
.requestMatchers("/my/**").hasAnyRole("ADMIN", "USER")
.anyRequest().authenticated());
return http.build();
}
}
인가 작업을 위해서 Configuration을 작성해야 한다.
일반적으로 Configuration 파일을 작성하는 것처럼 클래스 상단에 @Configuration 을 붙이고, 빈 상단에 @Bean을 붙인다.
@EnableWebSecurity는 스프링 시큐리티를 활성화하고 웹 보안 설정을 구성하는 데 사용된다.
앞서 설명했던 SecurityFilterChain을 빈으로 등록하여 사용한다. 이때 파라미터로 HttpSecurity를 받고, 예외는 던져준다.
HttpSecurity의 authorizeHttpRequests()를 사용하여 권한을 커스터마이징할 수 있다. authorizeHttpRequests() 메서드의 파라미터로 Customizer를 구현해 넘겨주면 되는데, 자바 8 문법에 따라서 람다형식으로 작성해주었다. 커스터마이저로는 권한을 설정하는 인가 작업(Authorization)을 하게 된다.(일종의 필터 설정)
url 매칭과 관련해서는 requestMatchers()를 사용한다. 파라미터로 넘겨주는 url 패턴은 와일드카드 패턴을 따라서 작성해주면 된다. 그리고 바로 다음에 권한 관련 메서드를 호출한다.
permitAll()hasRole("RoleName")hasAnyRole("Role1", "Role2")그리고, url 매칭이 필요없는 나머지 요청들에 대해서는 anyRequest().authenticated()로 접근 권한을 줄 수 있다.
마지막으로, 설정한 HttpSecurity의 build() 메서드를 호출하여 리턴하면 된다.
권한 부여 메서드는 먼저 작성된 것부터 적용에 높은 우선순위를 갖기 때문에, 세부적인 권한부터 먼저 설정해야한다. 넓은 범위에 대한 권한 설정은 후단에 해준다.(anyRequest()와 같은)
스프링 시큐리티는 voter 기반 아키텍쳐로, voter들은 configuration attributes 위에서 동작하며 이는 자원들을 보호하기 위함이다.(예시 : 메서드 호출, 서블릿 호출)
대표적인 voter로 RoleVoter가 있다. RoleVoter는 ROLE_ 접두사가 붙은 attribute를 찾아 권한을 줄 수 있는지 vote하게 된다. 그래서 DB에 저장하기 위해 엔티티에 역할을 부여할 때는 ROLE_ 접두사를 붙여서 주어야한다.
하지만 configuration에서 사용하는 일부 권한 부여 메서드들에는 자동으로 ROLE_ 접두사를 붙여준다. 그렇기 때문에 hasRole(), hasAnyRole() 에서 파라미터로 넘겨주는 Role 이름들에는 접두사를 붙이지 않는다.
/admin 경로로 접근했을 때 ADMIN 권한이 없으면 접근할 수 없도록 필터를 설정해두었다. 그래서 권한 없이 /admin 경로로 접근하면 다음과 같이 403 에러를 보여주며 접근이 거부됐다고 알려준다.
