
1. 암호화
1) 단방향 : 복구화가 안됨 / HASH
ex) SHA-512, BCrypt
2) 양방향
대칭키 : 키 교환이 어려워 상대방이 확인할 수 없음
디피-헬만(Diffie-Hellman) 알고리즘을 사용해서 서로만 알 수 있는 수학적 키를 교환
암호화해서 데이터 전송은 가능하나 신원 인증을 못함
비대칭키 : RSA
공형 암호
2. Junit으로 테스트하기
- 아무 sault나 막 붙일 수 없음
package shop.mtcoding.blog._core.util;
import org.junit.jupiter.api.Test;
import org.mindrot.jbcrypt.BCrypt;
public class BCryptTest {
@Test
public void hashpw_test(){
String rawPassword = "1234";
String encPassword = BCrypt.hashpw(rawPassword,"_jooho");
System.out.println(encPassword);
}
}

- gensalt 사용하기
- 키 값이 매번 달라짐
package shop.mtcoding.blog._core.util;
import org.junit.jupiter.api.Test;
import org.mindrot.jbcrypt.BCrypt;
public class BCryptTest {
@Test
public void gernsault_test() {
String sault = BCrypt.gensalt();
System.out.println(sault); // 값이 매번 달라짐
}
@Test
public void hashpw_test(){
String rawPassword = "1234";
String encPassword = BCrypt.hashpw(rawPassword,"_jooho");
System.out.println(encPassword);
}
}




3. 더미 데이터에 password값을 암호화된 값으로 변경
insert into user_tb(username, password, email, created_at) values('ssar', '$2a$10$r86ew9RpjFF8kNfY1jiqRe', 'ssar@nate.com', now());
insert into user_tb(username, password, email, created_at) values('cos', '$2a$10$r86ew9RpjFF8kNfY1jiqRe', 'cos@nate.com', now());
insert into board_tb(title, content, user_id, created_at) values('제목1', '내용1', 1, now());
insert into board_tb(title, content, user_id, created_at) values('제목2', '내용2', 1, now());
insert into board_tb(title, content, user_id, created_at) values('제목3', '내용3', 1, now());
insert into board_tb(title, content, user_id, created_at) values('제목4', '내용4', 2, now());
insert into board_tb(title, content, user_id, created_at) values('title5', '내용5', 2, now());
insert into board_tb(title, content, user_id, created_at) values('title6', '내용6', 2, now());
insert into board_tb(title, content, user_id, created_at) values('title7', '내용7', 2, now());
insert into board_tb(title, content, user_id, created_at) values('title8', '내용8', 2, now());
insert into board_tb(title, content, user_id, created_at) values('title9', '내용9', 2, now());
insert into reply_tb(comment, board_id, user_id, created_at) values('댓글1', 1, 1, now());
insert into reply_tb(comment, board_id, user_id, created_at) values('댓글2', 4, 1, now());
insert into reply_tb(comment, board_id, user_id, created_at) values('댓글3', 4, 1, now());
insert into reply_tb(comment, board_id, user_id, created_at) values('댓글4', 4, 2, now());

4. UserRepository에 findById 만들기
- 매번 암호화되어 값이 달라지기 때문에 findByUsernameAndPassword을 사용할 수 없음
- user 객체에 id를 찾아서 순수한 password과 받은 password의 해쉬 값이랑 비교
package shop.mtcoding.blog.user;
import jakarta.persistence.EntityManager;
import jakarta.persistence.Query;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import shop.mtcoding.blog.board.BoardResponse;
import java.util.List;
@Repository // IoC에 new하는 방법
public class UserRepository {
// DB에 접근할 수 있는 매니저 객체
// 스프링이 만들어서 IoC에 넣어둔다.
// DI에서 꺼내 쓰기만 하면된다.
private EntityManager em; // 컴포지션
// 생성자 주입 (DI 코드)
public UserRepository(EntityManager em) {
this.em = em;
}
@Transactional // db에 write 할때는 필수
public void save(UserRequest.JoinDTO requestDTO){
Query query = em.createNativeQuery("insert into user_tb(username, password, email, created_at) values(?,?,?, now())");
query.setParameter(1, requestDTO.getUsername());
query.setParameter(2, requestDTO.getPassword());
query.setParameter(3, requestDTO.getEmail());
query.executeUpdate();
}
public User findByUsernameAndPassword(UserRequest.LoginDTO requestDTO) {
Query query = em.createNativeQuery("select * from user_tb where username=? and password=?", User.class); // 알아서 매핑해줌
query.setParameter(1, requestDTO.getUsername());
query.setParameter(2, requestDTO.getPassword());
try { // 내부적으로 터지면 터지는 위치를 찾아서 내가 잡으면 됨
User user = (User) query.getSingleResult();
return user;
} catch (Exception e) {
throw new RuntimeException("아이디 혹은 비밀번호를 찾을 수 없습니다");
}
}
public User findByUsername(String username) {
Query query = em.createNativeQuery("select * from user_tb where username=?", User.class); // 알아서 매핑해줌
query.setParameter(1, username);
try { // 내부적으로 터지면 터지는 위치를 찾아서 내가 잡으면 됨
User user = (User) query.getSingleResult();
return user;
} catch (Exception e) {
throw new RuntimeException("아이디를 찾을 수 없습니다");
}
}
}
5. UserController에 /join수정하기
- user 객체에 id를 찾아서 순수한 password과 받은 password의 해쉬 값이랑 비교
package shop.mtcoding.blog.user;
import jakarta.servlet.http.HttpSession;
import lombok.AllArgsConstructor;
import org.mindrot.jbcrypt.BCrypt;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;
import shop.mtcoding.blog._core.util.Script;
@AllArgsConstructor
@Controller // 파일을 리턴함 -> @ResponseBody로 메세지 자체를 리턴
public class UserController {
// fianl 변수는 반드시 초기화 되어야 함
private final UserRepository userRepository; // null
private final HttpSession session;
// @AllArgsConstructor를 사용하면서 필요 없어짐
// public UserController(UserRepository userRepository, HttpSession session) {
// this.userRepository = userRepository;
// this.session = session;
// }
// 원래는 get요청이나 예외 post요청하면 됨
// 민감한 정보는 쿼리 스트링에 담아보낼 수 없음
//원래는 get요청이나 예외 post요청하면 됨
//민감한 정보는 쿼리 스트링에 담아보낼 수 없음
@PostMapping("/login")
public String login(UserRequest.LoginDTO requestDTO) {
String rawPassword= requestDTO.getPassword();
String encPassword= BCrypt.hashpw(rawPassword, BCrypt.gensalt());//레인보우 테이블에 안털림
requestDTO.setPassword(encPassword);
// 1. 유효성 검사
if(requestDTO.getUsername().length() < 3) {
throw new RuntimeException("username 길이가 너무 짧아요");
}
// 2. 모델 필요 select * from user_tb where username=? and password=?
User user = userRepository.findByUsername(requestDTO.getUsername()); // DB에 조회할때 필요하니까 데이터를 받음
// password 검증
if(BCrypt.checkpw(requestDTO.getPassword(), user.getPassword())){ // 순수한 password 넣기
throw new RuntimeException("패스워드가 틀렸습니다");
}
session.setAttribute("sessionUser", user);
return "redirect:/";
}
@PostMapping("/join")
public String join(UserRequest.JoinDTO requestDTO) {
System.out.println(requestDTO);
try{
userRepository.save(requestDTO);
} catch (Exception e) {
throw new RuntimeException("아이디가 중복되었어요"); // 위임시키면 로직의 변화없이 오류를 위임하고 끝남
}
return "redirect:/loginForm";
}
@GetMapping("/joinForm") // view만 원함
public String joinForm() {
return "user/joinForm";
}
@GetMapping("/loginForm") // view만 원함
public String loginForm() {
return "user/loginForm";
}
@GetMapping("/user/updateForm")
public String updateForm() {
return "user/updateForm";
}
@GetMapping("/logout")
public String logout() {
// 1번 서랍에 있는 uset를 삭제해야 로그아웃이 됨
session.invalidate(); // 서랍의 내용 삭제
return "redirect:/";
}
}


Share article