Spring Security란 무엇인가?
: 스프링 프레임워크 기반의 보안(인증과 권한 부여)을 다루기 위한 보안 프레임워크입니다.
스프링 시큐리티는 웹 애플리케이션, Restful 서비스, 메서드 수준의 보안까지 다양한 보안 요구사항을 지원하며, 많은 기능과 확장성을 제공하여 안전하고 효과적인 애플리케이션 보안을 구현하는 데 사용합니다.
Spring Security의 주요 기능과 개념
1. 인증(Authentication)
: 사용자의 신원을 확인하는 과정으로, 스프링 시큐리티는 다양한 인증 방식을 지원합니다.
기본적으로 form 기반의 로그인, HTTP 기본 인증, Remember Me 인증, OAuth, LDAP 등 다양한 인증 프로토콜을 지원합니다.
2. 권한 부여(Authorization)
: 인증된 사용자에게 특정한 권한과 역할(Role)을 부여하여 보호된 리소스(URL, 경로)에 대한 접근 권한을 관리합니다.
3. 세션 관리(Session Management)
: 웹 애플리케이션의 세션 관리를 보호하고, 세션 공격에 대비하여 세션 관리 기능을 제공합니다.
4. CSRF(Cross-Site Request Forgery)보호
: CSRF 공격으로부터 애플리케이션을 보호하기 우해 CSRF 토큰을 생성하고 검증하는 기능을 제공합니다.
Spring Security 사용 방법 및 기능 소개
1. Security 라이브러리를 build.gradle에 의존성 추가
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-security'
}
2. SecurityConfig 파일 작성
: Spring Security에서 관련된 설정을 하기 위해 필요한 Config 파일을 만듭니다.
@Configuration
@EnableWebSecurity // Security Filter를 등록
@EnableGlobalMethodSecurity(prePostEnabled = true) // 특정 주소로 접근시 권한 및 인증을 미리 체크
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.csrf().disable() // csrf 토큰 비활성화
.authorizeHttpRequests() // 어떤 request 요청이 온다면 ->
.antMatchers("/","/auth/**","/js/**", "/css/**", "/image/**") // 해당 경로들은 인증없이 이용 가능
.permitAll() // 접근 허용
.anyRequest() // 다른 요청들의 경우
.authenticated() // 인증이 필요함 - 없는 경우 접근 제한 페이지를 보여줌
.and() // and
.formLogin() // 로그인 폼 설정
.loginPage("/auth/loginForm") // 로그인 경로 설정
.defaultSuccessUrl("/"); // 로그인 성공시 리다이렉션 경로 설정
.logout()
.logoutSuccessUrl("/"); // 로그아웃 성공시 리다이렉션 경로 설정
return httpSecurity.build();
}
✔ Spring Security 어노테이션 이해하기
// 해당 클래스를 Configuration으로 등록
@Configuration
// Spring Security를 활성화 시키기
@EnabelWebSecurity
// Controller에서 특정 페이지에 특정 권한이 있는 유저만 접근을 허용할 경우 @PreAuthorize 어노테이션을 사용하는데,
// 해당 어노테이션에 대한 설정을 활성화시켜줍니다. (필수는 아닙니다.)
@EnableGlobalMethodSecurity(prePostEnabled = true)
✔ CSRF 보호 설정
httspSecurity.csrf().disable()
: CSRF 공격에 대한 방어를 해제하는 코드입니다.
기본적으로는 CSRF 공격에 대한 방어를 하도록 설정되어 있지만, 간단한 로그인 구현 하므로 해제하여 진행하였습니다.
✔ URL에 따른 페이지에 대한 권한 부여를 시작하는 메서드
authorizeHttpRequests() // 어떤 request 요청이 온다면
✔ 해당 URL 경로 권한 설정하기 - antMatchers()
antMatchers("/","/auth/**","/js/**", "/css/**", "/image/**") // 해당 경로들은 인증없이 이용 가능
permitAll() // 접근 허용
✔ 인증이 필요한 URL 경로 설정하기 - authenticated()
anyRequest() // 다른 요청들의 경우
authenticated() // 인증이 필요함 - 없는 경우 접근 제한 페이지를 보여줌
: anyRequest()를 통해 autMatchers()로 설정한 경로들을 제외한 나머지 경로들 모두를 설정할 수 있습니다.
authenticated()를 사용하여 해당 경로들은 인증이 필요한 URL로 설정합니다.
✔ Spring Security에서 지원하는 로그인 방식 설정하기
formLogin() // 로그인 폼 설정
loginPage("/auth/loginForm") // 로그인 경로 설정
defaultSuccessUrl("/") // 로그인 성공시 리다이렉션 경로 설정
: formLogin()을 사용하여 로그인 폼 설정 시작을 명시합니다.
loginPage() 메서드를 통해 Spring Security에서 제공할 로그인 페이지를 설정합니다.
( 로그인을 하지 않았을 경우 권한이 없는 페이지의 이용을 막고 로그인 페이지로 다시 redirect 하여, 인가되지 않은 사용자에게 보여줄 페이지를 설정할 수 있습니다.)
defaultSuccessUrl()은 로그인 성공 시 redirect 할 경로를 설정합니다.
✔ Spring Security에서 지원하는 로그아웃 방식 설정하기
logout() // 로그아웃 시 설정
logoutSuccessUrl() // 로그아웃 성공시 리다이렉트 주소
: logout을 사용하여 로그아웃 설정 시작을 명시합니다.
logoutSuccessUrl을 통해 로그아웃 성공시 redirect할 경로를 설정합니다.
3. Spring Security 회원가입과 비밀번호 암호화 설정
✔ BCryptPasswordEncoder 암호화 클래스를 이용해 인코딩하기
@Configuration
@EnableWebSecurity // Security Filter를 등록
public class SecurityConfig {
@Bean // password를 해쉬 함수를 적용해줌 - 암호화
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
: 회원가입 시 비밀번호를 작성하면 Spring Security는 인코딩 함수를 이용해 암호화하여 데이터베이스에 저장합니다.
로그인할 때도 입력한 값은 인코딩하여 데이터베이스에 있는 값과 비교하여 같은 경우 로그인을 허용하고 아닌 경우 로그인이 되지 않습니다.
비밀번호를 인코딩함으로써 사용자의 비밀번호가 외부로 바로 노출되는 점을 막아줍니다.
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class UserService {
private final UserRepository userRepository;
private final BCryptPasswordEncoder bCryptPasswordEncoder;
@Transactional
public void save(User user){
validationDuplicateUser(user);
String encPassword = bCryptPasswordEncoder.encode(user.getPassword()); // password 암호화
user.setPassword(encPassword);
user.setRole(UserRole.USER);
userRepository.save(user);
}
}
BCryptPasswordEncoder 클래스의 encode() 함수를 통해 값을 암호화하여, UserRepository에 저장합니다.