사용자의 신원을 확인하는 과정이다. 사용자의 신원 확인 행위는 대표적으로 아이디 패스워드 기반의 로그인 또는 OAuth 2.0을 사용한 인증이 있다.
어플리케이션은 인증 영역과 인증되지 않은 영역으로 존재하고 인증 영역의 경우 특정 사용자의 개인정보를 확인하고 수정할 수 있는 영역이기 때문에 반드시 인증 영역에 대해서 특정 기능을 수행할 수 있거나 데이터 접근이 허용된 사용자인지에 대한 확인이 필요하다.
스프링 부트 웹어플리케이션에 적용이 가능한 보안 관련 dependency으로 사용자 인증과 인가 처리를 기본으로 제공하고 다양한 커스터마이징이 가능한 것이 특징이다.
필터 체인 관련 전역 설정을 처리할 수 있는 API를 제공한다.
@Configuration
@EnableWebSecurity
public class WebSecurityConfigure extends WebSecurityConfigurerAdapter {
@Override
public void configure(WebSecurity web) {
//스프링 보안과 관련된 필터체인을 거치지 않는
//url을 설정하여 불필요한 서버 자원 낭비 예방
web.ignoring().antMatchers("/assets/**");
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//임시 유저 생성
auth.inMemoryAuthentication()
.withUser("user").password(passwordEncoder().encode("{noop}user123")).roles("USER")
.and()
.withUser("admin").password(passwordEncoder().encode("{noop}admin123")).roles("ADMIN");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
//세부적인 웹 보안기능 설정처리 API
http
//공개 리소스 또는 보호받는 리소스에 대한 세부 설정
.authorizeRequests()
.antMatchers("/me").hasAnyRole("USER", "ADMIN")
.anyRequest().permitAll()
.and()
//로그인 폼 기능 세부설정
.formLogin()
.defaultSuccessUrl("/")
.permitAll()
.and()
//쿠키를 사용한 자동 로그인 기능 활성화
.rememberMe()
.rememberMeParameter("remember-me")
.tokenValiditySeconds(300)
.and()
//로그아웃 설정
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/")
.invalidateHttpSession(true)
.clearAuthentication(true)
;
}
}
사용자의 비밀번호의 경우 원문을 그대로 사용하지 않고 패스워드 해시 알고리즘을 적용해서 사용하는 것이 보안상 권장되기 때문에 PasswordEncoder를 사용해야한다. Spring Security 5에서는 DelegatingPasswordEncoder 클래스가 기본 PasswordEncoder로 사용된다.
public static PasswordEncoder createDelegatingPasswordEncoder() {
Map<String, PasswordEncoder> encoders = new HashMap<>();
encoders.put("bcrypt", new BCryptPasswordEncoder());
encoders.put("ldap", new org.springframework.security.crypto.password.LdapShaPasswordEncoder());
encoders.put("MD4", new org.springframework.security.crypto.password.Md4PasswordEncoder());
encoders.put("MD5", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("MD5"));
encoders.put("noop", org.springframework.security.crypto.password.NoOpPasswordEncoder.getInstance());
encoders.put("pbkdf2", new Pbkdf2PasswordEncoder());
encoders.put("scrypt", new SCryptPasswordEncoder());
encoders.put("SHA-1", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("SHA-1"));
encoders.put("SHA-256",
new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("SHA-256"));
encoders.put("sha256", new org.springframework.security.crypto.password.StandardPasswordEncoder());
encoders.put("argon2", new Argon2PasswordEncoder());
return new DelegatingPasswordEncoder(encodingId, encoders);
}