Spring Security는 Spring 기반의 애플리케이션의 보안(인증과 권한, 인가 등)을 담당하는 스프링 하위 프레임워크이다.
많은 보안 옵션을 제공해주어 개발자가 보안 로직을 하나씩 작성하지 않아도 되는 장점이 있다.
implementation 'org.springframework.boot:spring-boot-starter-security'
testImplementation 'org.springframework.security:spring-security-test'
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
이전에는 WebSecurityConfigurerAdapter
를 상속 받아 사용했지만, Spring Security 5.7 이상에서는 이를 지원하지 않아 SecurityFilterChain
를 사용하여 구현한다.
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
}
@EnableWebSecurity는 WebSecurityConfiguration.class, SpringWebMvcImportSelector.class, OAuth2ImportSelector.class, HttpSecurityConfiguration.class들을 import해서 실행 시켜준다. 해당 애노테이션이 있어야 Security를 활성화 시킬 수 있다.
WebSecurityCustomizer
를 Bean으로 등록하여 필터 적용에 제외 시킬 것을 작성한다.
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
// 정적 자원에 스프링 시큐리티 필터 규칙을 적용하지 않도록 설정
return (web) -> web.ignoring().requestMatchers(PathRequest.toStaticResources().atCommonLocations());
}
HttpSecurity
는 스프링 시큐리티의 대부분 설정을 담당한다.
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeRequests()
...
.and()
.formLogin()
...;
return http.build();
}
.authorizeRequests() 는 리소스 접근 권한을 설정한다.
http
.authorizeRequests()
.antMatchers("/", "/register").permitAll()
.antMatchers("/admin/**").hasAnyRole("ADMIN")
.anyRequest().authenticated()
andMatchers
antMatchers("/", "/register")
permitAll
.antMatchers("/", "/register").permitAll()
hasAnyRole
antMatchers("/admin/**").hasAnyRole("ADMIN")
anyRequest
anyRequest().authenticated()
http
.formLogin()
.loginPage("/login")
.permitAll()
.defaultSuccessUrl("/")
.successHandler(customOAuthSuccessHandler)
.failureUrl("/login")
.and()
.logout()
.logoutSuccessUrl("/")
.permitAll();
formLogin
formLogin()
loginPage
loginPage("/login")
defaultSuccessUrl
.defaultSuccessUrl("/")
successHandler
.successHandler(customOAuthSuccessHandler)
failureUrl
.failureUrl("/login")
logout
logout()
.logoutSuccessUrl
logoutSuccessUrl("/")
임의의 계정 정보를 지정하여 기본 인증을 진행한다.
AuthenticationManagerBuilder
를 이용해 로그인 인증 처리를 한다.
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("test").password(passwordEncoder().encode("1234"))
.authorities("ROLE_USER");
}
inMemoryAuthentication
auth.inMemoryAuthentication()
withUser.password
withUser("test").password(passwordEncoder().encode("1234")).authorities("ROLE_USER")
DB에 있는 사용자 정보를 이용해 인증을 진행한다.
private final DataSource dataSource;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth)
throws Exception {
auth.jdbcAuthentication()
.dataSource(dataSource)
.passwordEncoder(passwordEncoder())
.usersByUsernameQuery("select username, password, enabled "
+ "from user "
+ "where username = ?")
.authoritiesByUsernameQuery("select u.username, r.authority "
+ "from user_role ur inner join user u on ur.user_id = u.id "
+ "inner join role r on ur.role_id = r.id "
+ "where u.username = ?");
}
jdbcAuthentication
auth.jdbcAuthentication()
dataSource
dataSource(dataSource)
usersByUsernameQuery
usersByUsernameQuery("select username, password, enabled from user where username = ?")
authoritiesByUsernameQuery
authoritiesByUsernameQuery("select u.username, r.authority from user_role ur inner join user u on ur.user_id = u.id inner join role r on ur.role_id = r.id where u.username = ?");
passwordEncoder
passwordEncoder(passwordEncoder())
@Bean
public static PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}