Spring Security는 Spring 기반 애플리케이션의 보안을 담당하는 강력한 프레임워크
주로 두 가지 핵심 기능인 인증과 권한 부여를 제공한다.
// Spring Security
implementation 'org.springframework.boot:spring-boot-starter-security'
Spring Security를 커스텀 설정하기 위해 SecurityConfig를 추가한다.
@EnableWebSecurity
@Configuration
public class SecurityConfig {
private final String[] allowUris = {
"/swagger-ui/**",
"/swagger-resources/**",
"/v3/api-docs/**",
"/auth/**"
};
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(requests -> requests
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
// 폼로그인 비활성화
.formLogin(AbstractHttpConfigurer::disable)
.logout(logout -> logout
.logoutUrl("/logout")
.logoutSuccessUrl("/login?logout")
.permitAll()
);
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
SecurityFilterChain
requestMatchers() 메소드를 사용하여 특정 URL 패턴에 대한 접근 권한을 설정한다.permitAll()은 인증 없이 접근 가능한 경로를 지정한다.hasRole("ADMIN")은 'ADMIN' 역할을 가진 사용자만 접근 가능하도록 제한한다.anyRequest().authenticated()는 그 외 모든 요청에 대해 인증을 요구한다.내가 진행하는 프로젝트의 경우 운영자 등 별도의 권한이 부여된 계정이 없어 role 부분은 삭제했다.
defaultSuccessUrl("/"): 성공 시 리다이렉트할 경로 @PostMapping("/auth/signup/email")
public ApiResponse<Void> emailSignup(@Valid @RequestBody MemberReqDto.SignupDto dto){
memberService.emailSignup(dto);
return ApiResponse.success(null);
}
@Transactional
@Override
public void emailSignup(MemberReqDto.SignupDto dto) {
String email = dto.getEmail();
checkEmailDuplicate(email);
if (!emailCodeRepository.existsByEmailAndVerifiedIsTrue(email)){
throw new AuthException(AuthErrorCode.INVALID_EMAIL);
}
while(true){
String nickname = nicknameGenerator.generate();
String salt = passwordEncoder.encode(dto.getPassword());
try {
Member member = MemberConverter.toMember(dto, salt, nickname);
memberRepository.save(member);
return;
} catch (DataIntegrityViolationException e) {
//재시도
}
}
}
@Transactional: db에서 조회를 하기 때문에 트랜잭션 처리를 했다.
가입 전 이메일 중복검사
랜덤 닉네임을 가입 시 부여해야해서, NicknameGenerator 클래스를 구현하였다. 다만, 닉네임 중복도 확인해야 하는데 여러 사용자가 동시에 회원가입 중에 정말 우연히도 닉네임이 겹치게 부여되어 에러가 나는 상황을 방지하고자 가입 로직에 while문을 사용하여 혹시라도 중복된 닉네임이면 여러 번 시도하도록 구현함.
하지만 보통은 그냥 memberRepository.save(member);만 쓰면 된다.
비밀번호 암호화: 레인보우 테이블 공격을 방지하기 위해, BCrypt를 사용하여 내부적으로 랜덤 솔트를 포함한 단방향 해시로 비밀번호를 저장
db에 암호화된 비밀번호가 저장되었다.
