본문 바로가기
공부/Spring

[Spring] 스프링 시큐리티 기본 설정 및 BcryptPasswordEncoder를 사용하여 비밀번호 암호화하기

by 웅대 2023. 1. 29.
728x90
반응형

유저의 아이디, 비밀번호를 서버에 저장할 때 비밀번호 자체를 서버에 저장하면 위험할 것이다.

 

그래서 비밀번호 같은 정보는 암호화를 한 다음에 서버에 저장하는 것이 안전하다.

 

스프링에서는 BcryptPasswordEncoder를 사용해서 이를 구현할 수 있다.

 

먼저 BcryptPasswordEncoder를 사용하기 위해서는 Spring Security를 받아야한다.

 

Build.gradle의 dependencies에 다음 코드를 추가하고 코끼리를 누른다.

implementation 'org.springframework.boot:spring-boot-starter-security'

스프링 시큐리티를 사용하게 되면 기본적으로 api를 요청할 때마다 사용자 인증을 거쳐야한다.

 

아무런 설정도 하지 않고 그냥 api를 호출하게 되면 인증되지 않았기 때문에 오류가 발생한다.

 

그래서 다음과 같이 configuration 패키지 안에 SecurityConfig 클래스를 만들어 기본 설정을 하고 빈으로 등록한다.

 

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception{
        return httpSecurity
                .httpBasic().disable()
                .csrf().disable()
                .cors().and()
                .authorizeRequests()
                .requestMatchers("/api/users/login", "/api/users/join").permitAll()
                .and()
                .build();
    }
}

위 설정을 간단히 설명하자면 /api/users/login과 api/users/join api는 인증을 거치지 않아도 혀용해준다는 뜻이다.

 

본 포스팅은 BcryptPasswordEncoder 기본 사용법을 설명하기 위한 포스팅이므로 api 접근을 허용해주는 정말 기본 설정만 해주었다.

 

또한 encoder 사용의 편의를 위해 BcryptPasswordEncoder도 빈으로 등록해준다.

@Configuration
public class EncoderConfig {
    @Bean
    public BCryptPasswordEncoder encoder() {
        return new BCryptPasswordEncoder();
    }
}

 

암호화 메소드

 

BcryptPasswordEncoder 안의 encdoe 메소드를 사용한다. encode 메소드 구현을 보면

@Override
public String encode(CharSequence rawPassword) {
   if (rawPassword == null) {
      throw new IllegalArgumentException("rawPassword cannot be null");
   }
   String salt = getSalt();
   return BCrypt.hashpw(rawPassword.toString(), salt);
}

인자로 비밀번호 평문을 받으면 암호화한 String 값을 반환한다.

 

비밀번호 일치 체크 메소드

 

BcryptPasswordEncoder 안의 matches 메소들르 사용한다. matches 메소드 구현을 보면

@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
   if (rawPassword == null) {
      throw new IllegalArgumentException("rawPassword cannot be null");
   }
   if (encodedPassword == null || encodedPassword.length() == 0) {
      this.logger.warn("Empty encoded password");
      return false;
   }
   if (!this.BCRYPT_PATTERN.matcher(encodedPassword).matches()) {
      this.logger.warn("Encoded password does not look like BCrypt");
      return false;
   }
   return BCrypt.checkpw(rawPassword.toString(), encodedPassword);
}

첫 번째 인자로 입력받은 비밀번호 평문을 넣어주고 두 번째 인자로 서버에 저장되어있는 암호화된 비밀번호를 넣어주면 Boolean 값을 반환한다.

dlwp UserService에서 회원가입할 때는 비밀번호를 암호화해서 저장하고 로그인할 때는 비밀번호가 맞는지 확인하는 코드를 만들어보려한다.

 

@Service
@RequiredArgsConstructor
public class UserService {
    private final UserRepository userRepository;
    private final BCryptPasswordEncoder encoder;

    public String join(String userId, String userPwd) {
        if (userRepository.findByUserId(userId).isPresent()){
            return "아이디가 존재합니다.";
        }
        User newUser = new User();
        newUser.setUserId(userId);
        newUser.setUserPwd(encoder.encode(userPwd));
        userRepository.save(newUser);
        return "회원가입 성공!";
    }

    public String login(String userId, String userPwd) {
        Optional<User> user = userRepository.findByUserId(userId);
        if (user.isEmpty()) {
            return "해당 유저를 찾지못했습니다.";
        }
        if (encoder.matches(userPwd, user.get().getUserPwd())) {
            return "로그인 성공!";
        }
        return "비밀번호가 일치하지 않습니다";

    }

}

BcryptPasswordEncoder를 private final로 지정하고 @RequiredArgsConstructor 어노테이션을 달아서 빈으로 등록한 encoder를 주입받도록 한다.

728x90
반응형

댓글