Complete to Signup, and Password Hashing Structure

민준·2023년 2월 24일
0
post-thumbnail

1. 회원가입 완료하기

지난 글에 큰 문제를 만나 약 이틀을 그 문제를 해결하는 데에 소비했습니다.
아무튼 문제의 원인을 추측해서 문제를 해결을 했으니 다음에 비슷한 문제를 만나면
하나의 원인을 더 생각해볼 수 있게 되었습니다.

이번에는 지난 번 연동한 데이터베이스에 데이터 값을 전송합니다.
목적은 'SignupDto'의 데이터를 'User' 테이블의 필드에 맞게 넣는 것입니다.

SignupDto.java

함수를 하나 만들어 줍니다.

@Data
public class SignupDto {
	
	private String username;
	private String password;
	private String email;
	private String name;
	
	public User toEntity() {
		return User.builder() // 빌더패턴 사용
				.username(username)
				.password(password)
				.email(email)
				.name(name)
				.build();
	}
}

4개의 데이터를 기반으로 유저 객체가 만들어집니다.

AuthController.java

지난번에 만든 'POST' 회원가입 도메인에 코드를 추가합니다.

@PostMapping("/auth/signup")
public String signup(SignupDto signupDto) {
	log.info(signupDto.toString());
	User user = signupDto.toEntity();
	log.info(user.toString());			   // 데이터가 잘 넘어오는지 콘솔창에서 확인
	return "auth/signin";
}

그리고 도메인에 접속해 회원가입을 시도하면 데이터가 필드에 맞게 넘어오는 것을 확인할 수 있습니다.
데이터가 입력되지 않은 필드는 null 값이 들어갔습니다.

AutoService.java

이제 이렇게 넘어오는 데이터를 데이터베이스에 넘길텐데, 그러기 위해서는 서비스가 필요합니다.
'com.cos.photogramstart' 아래에 'service' 패키지를 만들고 그 안에 'AutoService' 클래스를 만듭니다.
그리고 회원가입 메서드는 회원가입 진행을 하는데, 그러기 위해서는 레파지토리가 필요합니다.

package com.cos.photogramstart.service;

import org.springframework.stereotype.Service;

import com.cos.photogramstart.domain.user.User;

@Service // 1.IoC 등록, 2. 트랜잭션 관리
public class AuthService {
	
	public void 회원가입(User user) {
		// 회원가입 진행을 위해서는 repository 가 필요합니다.
		
	}
}

UserRepository.java

'domain.user' 아래에 이 클래스를 만듭니다.

package com.cos.photogramstart.domain.user;

import org.springframework.data.jpa.repository.JpaRepository;

// 어노테이션이 없어도 'JpaRepository'를 상속하면 IoC 등이 자동으로 됩니다.
public interface UserRepository extends JpaRepository<User, Integer>{

}

'AuthController'에 아래의 코드를 추가합니다.

@RequiredArgsConstructor // final 필드를 DI 할 때 사용합니다.
@Controller 			 // 1. IoC 등록, 2. 파일을 리턴합니다.
public class AuthController {
	
private static final Logger log = LoggerFactory.getLogger(AuthController.class);
	
@Autowired
private final AuthService authService;

'AutoService'의 코드를 수정합니다.

package com.cos.photogramstart.service;

import org.springframework.stereotype.Service;

import com.cos.photogramstart.domain.user.User;
import com.cos.photogramstart.domain.user.UserRepository;

import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
@Service // 1.IoC 등록, 2. 트랜잭션 관리
public class AuthService {
	
	private final UserRepository userRepository;
	
	public User 회원가입(User user) {
		// 회원가입 진행을 위해서는 repository 가 필요합니다.
		
		User userEntity = userRepository.save(user); // 데이터를 받아 저장합니다.
		return userEntity;
	}
}

'AutoController'의 코드를 수정합니다.

@PostMapping("/auth/signup")
public String signup(SignupDto signupDto) {

	log.info(signupDto.toString());
	User user = signupDto.toEntity();
	log.info(user.toString());
	User userEntity = authService.회원가입(user);
	System.out.println(userEntity);
	return "auth/signin";
}

지금 상태로 가입을 시도하면, id 값이 없다는 오류가 나게 됩니다.
지난번에 id 값을 자동으로 데이터베이스에 쌓이도록 했는데 이상합니다.
테이블의 스키마를 변경하려면 ddl-auto: create 로 저장해야해서 다시 실행해야합니다.
그러면 콘솔창에 'Hibernate: create table User (id integer not null auto_increment, ...)이 뜨게 됩니다.
사실 저는 이미 되어있습니다. 이후 ddl-auto: update 로 수정하고 저장합니다.
이 'ddl' 설정은 'application.yml'에 있습니다.

이제 회원가입을 시도하면 id 값이 1이되고 잘 들어갑니다.
실제로 잘 들어갔는지 DB를 확인해보면 잘 들어가있습니다.

위 프로그램은 'Sequel Pro'라는 데이터베이스 GUI 프로그램입니다.
photogram 데이터베이스의 User 테이블에 필드와 데이터가 잘 들어갔습니다!

하지만 비밀번호가 암호화되지 않았습니다.


2. password 암호화

'AutoService'의 회원가입 메서드에 어노테이션을 추가합니다.

@Transactional // 함수가 실행되고 종료될 때까지 트랜잭션 관리합니다. Write(Insert, Update, Delete)
public User 회원가입(User user) {
	User userEntity = userRepository.save(user);
	return userEntity;
}

SecurityConfig

'BCrypt' 암호화를 하며 이곳에 빈 등록을 합니다.
'SecurityConfig'가 IoC에 등록될 때 'Bean' 어노테이션을 읽어서 암호화인코더를 들고있습니다.

@Bean
public BCryptPasswordEncoder encode() {
	return new BCryptPasswordEncoder();
}

'AuthService'에서 위의 암호화인코더를 사용합니다.

@RequiredArgsConstructor
@Service
public class AuthService {
	
	private final UserRepository userRepository;
	private final BCryptPasswordEncoder bCryptPasswordEncoder;
	
	@Transactional
	public User 회원가입(User user) {
		
		String rawPassword = user.getPassword();
		String encPassword = bCryptPasswordEncoder.encode(rawPassword);
		// 입력한 비밀번호를 encPassword에 넣을 때 해시로 암호화합니다.
		
		user.setPassword(encPassword);
        
        ...
	}

3. 권한 설정

바로 위의 'AuthService'의 회원가입 메서드 코드에 권한 설정 코드를 추가합니다.

		...
        
		String rawPassword = user.getPassword();
		String encPassword = bCryptPasswordEncoder.encode(rawPassword);
		
		user.setPassword(encPassword);
		user.setRole("ROLE_USER"); // 회원가입 하는 모든 사용자의 권한을 ROLE_USER, 관리자는 ROLE_ADMIN
		User userEntity = userRepository.save(user);
		return userEntity;
	}
}

회원가입을 진행해봅니다.

비밀번호가 암호화되고 이 캡쳐에선 안보이지만 권한도 설정되었습니다.
다만 아직 문제가 남았는데, 중복이 걸러지지 않습니다.
계정을 만들 때 계정을 고유의 것인데, 같은 아이디로 만들어도 계정은 만들어 집니다.


4. 중복 계정 가입 처리

일단 'ddl-auto: create'로 변경해서 저장합니다.

User.java

이 클래스의 속성값 username 위에 제한조건을 설정합니다.
그리고 'ddl-auto: update'로 변경해서 저장합니다.
콘솔창에 이런 문장이 하나 추가로 뜹니다.
'Hibernate: alter table User add constraint UK_jreodf78a7pl5qidfh43axdfb unique (username)'
그럼 이제 중복을 인정하지 않습니다. 어노테이션이 참 편리합니다.

@Column(unique = true)
private String username;
private String password;

콘솔창에서의 쿼리문 말고도, 아래처럼 'DESC user;' 이라는 쿼리문을 통해
username 이 unique인지 확인할 수 있습니다.

이제 만약 중복되는 username으로 가입을 시도한다면 500번 오류 창이 나타납니다.

profile
백엔드 포지션 공부 중입니다.

0개의 댓글