본문 바로가기

Spring boot/Bank App 만들기(deployment)

Bank App 만들기 ( deployment ) - 사용자 비밀번호 암호화 처리

마이그레이션이란?

데이터베이스 스키마의 변경 내역을 버전 관리하여, 변경에 대한 이력을 남기고, 데이터베이스를 이전 버전에서 최신 버전으로 옮기는 일련에 과정들을 의미한다. 즉, 일반적으로 마이그레이션은 스키마를 변경하거나 새로운 테이블이나 컬럼을 추가하는 등에 작업을 포함하고 따라서 우리가 할 작업 H2 데이터베이스에서 MySQL 로 변경할 때도 마이그레이션을 수행 한다고 할 수 있다. 이러한 이경우에 테이터 스키마를 변경하거나 데이터를 이전하는 작업등이 포함 될 수 있다.

 

 

 

SpringSecurityCrypto 의존성 추가 및 BCryptPasswordEncoder 빈 클래스로 등록

주의 : spring-security 에서 제공하는 crypto라는 라이브러리를 활용한다. 이번 프로젝트에서는 Spring Security를 활용하지 않는다.

 

 

Spring Security Crypto

org.springframework.security:spring-security-crypto 모듈은 스프링 시큐리티 프레임워크의 일부로, 암호화와 해싱을 위한 기능을 제공한다. 이 모듈은 비밀번호 저장, 데이터 암호화 및 디지털 서명을 위한 API를 포함하며, 개발자가 보안 관련 작업을 보다 쉽게 구현할 수 있도록 돕는다. 주로 사용되는 기능은 비밀번호 인코딩(해싱)과 텍스트 데이터의 암호화/복호화이다.

 

 

의존성 추가 하기 - gradle 파일에 추가 후 새로 고침
// 암호화 
implementation 'org.springframework.security:spring-security-crypto'

 

 

 

 

주요 import 확인
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

 

 

 

WebMvcConfig - 코드 추가 (PasswordEncoder Bean 처리)
package com.tenco.bank.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import com.tenco.bank.handler.AuthInterceptor;

import lombok.RequiredArgsConstructor;

@Configuration   
@RequiredArgsConstructor
public class WebMvcConfig implements WebMvcConfigurer {
	
	@Autowired // DI
	private final AuthInterceptor authInterceptor;
	// @RequiredArgsConstructor <-- 생성자 대신 사용 가능
	
	// 우리가 만들어 놓은 AuthInterceptor 를 등록해야 함. 
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		registry.addInterceptor(authInterceptor)
			.addPathPatterns("/account/**")
			.addPathPatterns("/auth/**");
	}
	
	@Bean // IoC 대상(싱글톤 처리) 
	PasswordEncoder passwordEncoder() {
		return new BCryptPasswordEncoder();
	}
}

 

 

 

 

2. 회원가입 시 회원 비밀번호 암호화 처리

/**
	 * 회원 등록 서비스 기능
	 * 트랜잭션 처리  
	 * @param dto
	 */
	@Transactional // 트랜잭션 처리는 반드시 습관화 
	public void createUser(SignUpDTO dto) {
		
		int result = 0; 
		try {
			// 코드 추가 부분 
			// 회원 가입 요청시 사용자가 던진 비밀번호 값을 암호화 처리 해야 함 
			String hashPwd = passwordEncoder.encode(dto.getPassword());
			System.out.println("hashPwd : " + hashPwd);
			dto.setPassword(hashPwd);
			result = userRepository.insert(dto.toUser());
		} catch (DataAccessException e) {
			throw new DataDeliveryException("중복 이름을 사용할 수 없습니다.", HttpStatus.INTERNAL_SERVER_ERROR);
		} catch (Exception e) {
			throw new RedirectException("알 수 없는 오류", HttpStatus.SERVICE_UNAVAILABLE);
		}
		if(result != 1) {
			throw new DataDeliveryException("회원가입 실패", HttpStatus.INTERNAL_SERVER_ERROR);
		}
		
		
	}

 

 

 

 

3. 로그인 시 암호호 된 비번 확인 및 기능 추가

package com.tenco.bank.repository.interfaces;

import java.util.List;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import com.tenco.bank.repository.model.User;

// UserRepository 인터페이스와 user.xml 파일을 매칭 시킨다. 
@Mapper // 반드시 선언을 해야 동작한다. 
public interface UserRepository {
	
	public int insert(User user);
	public int updateById(User user);
	public int deleteById(Integer id);
	public User findById(Integer id);
	public List<User> findAll();
	
	  
	public User findByUsernameAndPassword(@Param("username") String username, @Param("password") String password);
	
	// 코드 추가 
	public User findByUsername(@Param("username") String username);
	
}

 

 

 

 

user.xml
<select id="findByUsername" resultType="com.tenco.bank.repository.model.User" >
	select * from user_tb where username = #{username}	
</select>
public User readUser(SignInDTO dto) {
		 
		User userEntity = null;  // 지역 변수 선언 
		try {
			userEntity = userRepository.findByUsername(dto.getUsername());
			
		} catch (DataAccessException e) {
			throw new DataDeliveryException("잘못된 처리 입니다.", HttpStatus.INTERNAL_SERVER_ERROR);
		} catch (Exception e) {
			throw new RedirectException("알수 없는 오류", HttpStatus.SERVICE_UNAVAILABLE);
		}
		
		if(userEntity == null) {
			throw new DataDeliveryException("존재하지 않는 아이디 입니다.", HttpStatus.BAD_REQUEST);
		}
		
		boolean isPwdMatched = passwordEncoder.matches(dto.getPassword(), userEntity.getPassword());
		if(isPwdMatched == false) {
			throw new DataDeliveryException("비밀번호가 잘못되었습니다", HttpStatus.BAD_REQUEST);
		}
		
		return userEntity;
	}
728x90