로그인, 회원가입 개발을 하다 보면 제일 많이 접근하고 자주 구현하게 되는 기능이 아닐까 싶다.
예전 막 개발을 시작했을 때는 아무런 기능 없이 회원가입 때 아이디와 비밀번호를 DB에 넣어주고 로그인할 때 회원가입 시 입력한 아이디, 비밀번호와 일치한 지 체크 후 로그인이 되는 단순한 방식으로 구현했던 기억이 있다.
하지만 이젠 레벨업이 어느정도 된 만큼 다양한 기능들을 통해 회원가입, 로그인을 구현하고자 한다.
Spring Security
Spring Security는 인증, 권한 부여 및 보호 기능 등을 제공하는 스프링 하위 프레임워크이다.
Spring 내에서 효과적으로 보안과 관련된 기능들을 효율적이고 신속하게 지원하고 구현할 수 있게 해 준다.
Spring Security는 보통 인증과 인가 절차를 거치게 된다.
- 인증(Authentication) : 해당 사용자 본인이 맞는지 확인하는 절차
- 인가(Authorization) : 인증 절차 후 인증된 사용자가 요청된 자원에 접근이 가능한지 확인하는 절차
Spring Security는 credential 기반의 인증 방식을 사용한다. credential 인증 방식이란 username과 password를 이용하는 방식으로 credential에서는 각각 username은 principal(아이디), password는 credential(비밀번호)를 의미한다.
정리하자면 특정 자원에 접근하여 제어하기 위해서는 특정 권한이 필요하고 그 권한을 얻기 위해 인증과 인가 절차를 거쳐야 하 이 절차에서 사용되는 방식이 credential이라 이해하면 되겠다.
이제 구현을 해보자 필요한 dependencies는 아래와 같다.
// build.gradle
plugins {
id 'java'
id 'org.springframework.boot' version '3.0.4'
id 'io.spring.dependency-management' version '1.1.0'
}
group = 'com.cac'
version = '0.0.1-SNAPSHOT'
java {
sourceCompatibility = '17'
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
implementation 'org.springframework.boot:spring-boot-starter-validation'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
// spring-data-jpa dependency
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
// maria-db
implementation group: 'org.mariadb.jdbc', name: 'mariadb-java-client', version: '3.0.8'
// spring-security dependency
implementation 'org.springframework.boot:spring-boot-starter-security'
testImplementation 'org.springframework.security:spring-security-test'
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
}
jar {
zip64 = true
enabled = false // plain 제거
}
tasks.named('test') {
useJUnitPlatform()
}
나중에 OAuth2를 사용한 소셜 로그인도 구현할 예정이라 OAuth2 dependencies도 미리 추가하였다.
그리고 SecurityConfig 파일을 작성해 주자
// SecurityConfig.java
@RequiredArgsConstructor
@Configuration
@EnableWebSecurity // Spring Security 활성화 및 웹 보안 설정 구성
public class SecurityConfig {
private final CorsConfig corsConfig;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.cors()
.configurationSource(corsConfig.corsConfigurationSource())
.and()
.formLogin().disable()
.csrf().disable() // rest api 사용시 disable / token을 사용하는 방식일 경우 disable
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeHttpRequests() // HttpServletRequest를 사용하는 요청들에 대한 접근제한을 설정하겠다.
.requestMatchers("/").permitAll()
.requestMatchers("/member/**").permitAll()
.requestMatchers("/lecture/auth/**").permitAll()
.requestMatchers("/faq/**").permitAll()
.requestMatchers("/board/**").permitAll()
.requestMatchers("/review/**").permitAll()
.requestMatchers("/favicon.ico").permitAll()
.anyRequest().authenticated();
return httpSecurity.build();
}
}
- PasswordEncoder
해당 인터페이스 부분은 이제 로그인 및 회원가입을 할 때 비밀번호를 암호화하기 위해 사용하였다.
BCryptPasswordEncoder는 BCrypt 해싱 함수를 사용하여 비밀번호를 인코딩해주는 메서드와 나중에 저장된 비밀번호와 입력한 비밀번호가 일치한 지 여부를 확인해 주는 메서드를 제공해 준다.
이 방법을 사용하면 DB에 비밀번호가 엄청 긴 문자열로 저장되는 것을 확인할 수 있다.
- CorsConfig
나는 프론트 부분을 React로 구현하다 보니 CORS 이슈가 발생하기에 아래와 같은 파일을 만들어 Security에 적용해 주는 것으로 해결하였다.
// CorsConfig.java
@Configuration
public class CorsConfig {
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(List.of("http://localhost:3000"));
configuration.setAllowedMethods(List.of("*"));
configuration.setAllowedHeaders(List.of("*"));
configuration.setAllowCredentials(true); // 쿠키를 받을 여부
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
- authorizeHttpRequest
로그인을 하지 않아도 접근할 수 있는 URL 자원을 지정해 주었다. 이를 통해 회원가입 및 로그인을 하지 않아도 웹사이트에서 특정 기능들을 사용할 수 있게 해 준다.
여기서 지정한 URL 외에는 모두 인증이 되지 않는 이상 사용할 수 없다.
이 부분은 원하는 대로 설정을 해주면 된다. 초기에는 requestMatchers("/", "/**").permitAll() 으로 설정해 주면 권한 없이 모든 자원에 접근하고 테스트할 수 있을 것이다.
여기까지만 해준다면 Spring Security 설정은 대략적으로 된 것이다.
이제 다음으로 JWT를 사용하기 위해 build.gradle과 SecurityConfig 파일에 추가적으로 작성해 주고 JWT와 관련된 여러 파일들을 작성해 주겠다.
관련 포스팅
2024.03.06 - [[개인프로젝트] 개발 공부] - [프로젝트] 6. Spring Security + JWT로 로그인 구현하기 (2)
2024.03.08 - [[개인프로젝트] 개발 공부] - [프로젝트] 7. Spring Security + JWT로 로그인 구현하기 (3)
2024.03.18 - [[개인프로젝트] 개발 공부] - [프로젝트] 8. Spring Security + OAuth2.0 (feat. JWT)로 간편 로그인 구현하기 (1)
2024.03.21 - [[개인프로젝트] 개발 공부] - [프로젝트] 9. Spring Security + OAuth2.0 (feat. JWT)로 간편 로그인 구현하기 (2)
'[개인프로젝트] 개발 공부' 카테고리의 다른 글
[프로젝트] 7. Spring Security + JWT로 로그인 구현하기 (3) (1) | 2024.03.08 |
---|---|
[프로젝트] 6. Spring Security + JWT로 로그인 구현하기 (2) (3) | 2024.03.06 |
[프로젝트] 4. React 상태 관리 라이브러리 - Zustand (1) | 2024.02.27 |
[프로젝트] 3. React 다크모드 구현하기 (0) | 2024.02.15 |
[프로젝트] 2. SPRINGBOOT 3.0 + Query DSL (0) | 2024.01.06 |