본문 바로가기
Spring boot 프로젝트 기록/3. 인증 백엔드 통합

패스워드 암호화

by 으노으뇨 2021. 12. 13.
728x90
반응형
SMALL

마지마긍로 패스워드를 암호화 해보겠습니다.

패스워드 암호화 부분은 스프링 시큐리티가 제공하는 BCryptPasswordEncoder의 사용을 위해 

구현을 잠시 미뤄뒀었습니다.

우리가 UserController와 UserService 를 구현할 당시에는 스프링 시큐리티 디펜던시를

설정하지 않았었기 때문입니다.

이제 Userservice를 수정해줍니다.

기존의 getByCredentials 매서드를 수정해주어야합니다.

	public UserEntity getByCredentials(final String email, final String password,
			final PasswordEncoder passwordEncoder) {
		final UserEntity originalUser = userRepository.findByEmail(email);
		// matches 메서드를 이용해 패스워드가 같은지 확인합니다.
		if (originalUser != null && passwordEncoder.matches(password, originalUser.getPassword())) {
			return originalUser;
		}
		return null;
	}

보통 암호화된 패스워드를 비교해야하는 경우 사용자에게 받은 패스워드를 같은 방법으로 

암호화한 후 그 결과를 데이터베이스의 값과 비교하는 것이 자연스러운 생각의 흐름이다.

그러나 우리는 그렇게 하지 않았습니다. 

matches매서드를 사용했습니다.

이유는 BCryptPasswordEncoder는 같은 값을 인코딩하더라도 할 때마다 값이 다르고 

패스워드에 랜덤하게 의미 없는 값을 붙여 결과를 생성하기 때문입니다.

이런 의미 없는 값을 보안 용어로 Salt라고 합니다. 

그런 Salt를 붙여 인코딩하는 것을 Salting이라고 합니다.

따라서 사용자에게 받은 패스워드를 인코딩해도 데이터베이스에 저장된 패스워드와는 다를 확률이 높습니다.

대신 BCryptPasswordEncoder는 어떤 두 값의 일치 여부를 알려주는 매서드인 matches()를 제공합니다.

이 매서드는 Salt를 고려해 두 값을 비교해 줍니다.

이에 수정한 코드에 맞추어 UserController도 수정해 주도록 해봅시다.

로그인을 할때 발생합니다.

package com.unoSpringBoot.study.Controller.User;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import com.unoSpringBoot.study.DTO.ResponseDTO;
import com.unoSpringBoot.study.DTO.UserDTO;
import com.unoSpringBoot.study.model.UserEntity;
import com.unoSpringBoot.study.security.TokenProvider;
import com.unoSpringBoot.study.service.UserService;

@Service
public class LoginUserCO {
	@Autowired
	private TokenProvider tokenProvide;
	@Autowired
	private UserService service;
	@Autowired
	private PasswordEncoder passwordEncoder;

	public ResponseEntity<?> authenticate(UserDTO userDTO) {
		UserEntity user = service.getByCredentials(userDTO.getEmail(), userDTO.getPassword(), passwordEncoder);
		if (user != null) {
			// 여기서 부터 토큰생성을 해주는 기능을 넣어준다!
			final String token = tokenProvide.create(user);
			final UserDTO responseUserDTO = UserDTO.builder().email(user.getUsername()).id(user.getId()).token(token)
					.build();
			return ResponseEntity.ok().body(responseUserDTO);
		} else {
			ResponseDTO<?> responseDTO = ResponseDTO.builder().error("로그인 실패 ㅠ").build();
			return ResponseEntity.badRequest().body(responseDTO);
		}
	}
}

@Autowired
private PasswordEncoder passwordEncoder;

로 빈으로 등록해주었습니다

이렇게 우리는 보안 측면에서 초보자로서 할 수 있는 일을 다 한셈입니다.

이렇게 우리는 성공적으로 API서비스 레벨에서 인증을 구현했고, 처음으로 몇까지 기본적인 인증과

인가방법을 살펴봤습니다.

이후 실제로 사용자 관리를 위한 User 레이어를 구현했습니다.

그런다음 모든 요청마다 한 번씩 사용자의 인증을 위해 스프링 시큐리티가 제공하는

OnecePerRequestFilter를 상속해 JwtAuthenticationFilter를 작성했습니다.

그리고 WebSecurityConfigurerAdapter를 상속해 어떤 경로는 인증을 해야하고, 

어떤경로는 인증을 하지않아도 되는지 또 우리가 구현한 jwtAuthenticationFilter를 어느 시점에서 실행할지도 설정했습니다.

다음포스팅부터는

프론트엔드에서 인증과 인가 로직을 구현하고 서비스와 통합하도록 하겠습니다.

 

728x90
반응형
LIST

댓글