This repository has been archived by the owner on Aug 13, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add 회원가입 기능 - 회원가입 기능을 통해 Careers를 로그인 한 사용자들만 이용할 수 있도록 한다. - 이름, 이메일, 비밀번호 모두를 입력 받는다.(Null 체크) - 이메일은 이메일 형식에 맞게 작성해야 한다. - 비밀번호는 문자, 숫자, 특수문자로 구성되어야 한다. - 비밀번호는 암호화하여 DB에 저장한다.(sha-256) - 중복된 이메일인지 체크하여 중복가입을 제한한다. #3 * Fix 디비 primary key id로 수정 * Fix 큐레이터 테이블 unique index 설정 * Fix 회원가입 http method 변경 put -> post * Fix 롬복사용하여 생성자 자동주입 * Fix 사용하지 않는 요청 메서드 제거 * Fix 이메일 중복 예외처리 * Fix http status code 처리 이메일, 비밀번호 위반 시 status code 반환하도록 수정 * Fix model코드 가독성 처리 * Fix 암호화코드와 유저서비스 기능 분리 단일책임원칙 적용 * Fix Select쿼리문 email컬럼 명시적으로 표현 * Fix mysql 사용자계정 변경 * Fix 롬복 Data 애노테이션 제거 명확한 의도를 설정하기위해 Data 애노테이션 대신 각각 설정 * Fix 롬복 애노테이션 정리 * Fix StringBuffer를 StringBuilder로 변경 여러 스레드가 해당 부분을 접근할 일이 현재로서는 없으므로 StringBuilder로 수정 * Fix 사용하지 않는 애노테이션 제거 * Update src/main/java/com/dev/careers/service/encryption/SHA256Encryption.java Fix 코딩 컨벤션 위반 수정 Co-authored-by: f-lab <54677861+f-lab-dev@users.noreply.github.com> * Fix 인터페이스, 클래스 명명규칙 수정 Encryption -> Encryptor 로 변경 * Fix 메소드 명명규칙 수정 * Fix 요청에따른 결과 반환 void로 수정 * Fix void반환으로 인한 테스트케이스 수정 * Fix 성능보완을 위해 쿼리로 중복검증 체크 * Fix 성능향상을 위해 쿼리문 수정 exists를 사용하여 쿼리성능향상 및 이메일 존재 유무에 대해 명확하게 표현 * Fix checkstyle 위반된 부분 수정 카멜케이스 적용 Co-authored-by: f-lab <54677861+f-lab-dev@users.noreply.github.com>
- Loading branch information
1 parent
fcf17ab
commit 60ed0cc
Showing
15 changed files
with
319 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
create table Curator( | ||
id int(10) not null auto_increment, | ||
email varchar(64) not null, | ||
name varchar(64) not null, | ||
password varchar(64) not null, | ||
salt varchar(64) not null, | ||
primary key (id), | ||
unique index idx_email (email) | ||
); |
34 changes: 34 additions & 0 deletions
34
src/main/java/com/dev/careers/controller/CuratorController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package com.dev.careers.controller; | ||
|
||
import com.dev.careers.model.Curator; | ||
import com.dev.careers.service.CuratorService; | ||
import com.dev.careers.service.error.ViolationException; | ||
import java.util.Optional; | ||
import javax.validation.Valid; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.validation.BindingResult; | ||
import org.springframework.validation.ObjectError; | ||
import org.springframework.web.bind.annotation.ModelAttribute; | ||
import org.springframework.web.bind.annotation.PostMapping; | ||
import org.springframework.web.bind.annotation.RestController; | ||
|
||
|
||
@RequiredArgsConstructor | ||
@RestController | ||
public class CuratorController { | ||
|
||
private final CuratorService curatorService; | ||
|
||
@PostMapping("/curators/join") | ||
public void putMember(@Valid @ModelAttribute Curator curator, BindingResult bindingResult) | ||
throws Exception { | ||
if (bindingResult.hasErrors()) { | ||
Optional<ObjectError> objectError = bindingResult.getAllErrors().stream().findFirst(); | ||
if (objectError.isPresent()) { | ||
throw new ViolationException(); | ||
} | ||
} | ||
|
||
curatorService.join(curator); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package com.dev.careers.mapper; | ||
|
||
import org.apache.ibatis.annotations.Mapper; | ||
import org.apache.ibatis.annotations.Param; | ||
|
||
@Mapper | ||
public interface CuratorMapper { | ||
|
||
Integer insertCurator( | ||
@Param("email") String email, | ||
@Param("name") String name, | ||
@Param("password") String password, | ||
@Param("salt") String salt); | ||
|
||
boolean checkEmailExists(@Param("email") String email); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package com.dev.careers.model; | ||
|
||
import javax.validation.constraints.Email; | ||
import javax.validation.constraints.Pattern; | ||
import lombok.Getter; | ||
import lombok.NonNull; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.lang.Nullable; | ||
|
||
@Getter | ||
@RequiredArgsConstructor | ||
public class Curator { | ||
@Nullable | ||
private int id; | ||
|
||
@NonNull | ||
@Email(message = "Email Format Violation") | ||
private String email; | ||
|
||
@NonNull | ||
private String name; | ||
|
||
//최소 8자리에 숫자, 문자, 특수문자 각각 1개 이상 포함 | ||
@Pattern(regexp = "^(?=.*[A-Za-z])(?=.*\\d)(?=.*[$@$!%*#?&])[A-Za-z\\d$@$!%*#?&]{8,}$", | ||
message = "Password Format Violation") | ||
@NonNull | ||
private String password; | ||
|
||
@Nullable | ||
private String salt; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package com.dev.careers.service; | ||
|
||
import com.dev.careers.mapper.CuratorMapper; | ||
import com.dev.careers.model.Curator; | ||
import com.dev.careers.service.encryption.PasswordEncryptor; | ||
import com.dev.careers.service.error.DuplicatedEmailException; | ||
import java.security.NoSuchAlgorithmException; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Service; | ||
|
||
@RequiredArgsConstructor | ||
@Service | ||
public class CuratorService { | ||
private final CuratorMapper curatorMapper; | ||
private final PasswordEncryptor passwordEncryptor; | ||
|
||
public void join(Curator curator) throws NoSuchAlgorithmException { | ||
//중복검증 | ||
if (curatorMapper.checkEmailExists(curator.getEmail())) | ||
throw new DuplicatedEmailException(); | ||
|
||
String salt = passwordEncryptor.makeSalt(); | ||
curatorMapper.insertCurator( | ||
curator.getEmail(), | ||
curator.getName(), | ||
passwordEncryptor.hashing(curator.getPassword().getBytes(), salt), | ||
salt); | ||
} | ||
} |
8 changes: 8 additions & 0 deletions
8
src/main/java/com/dev/careers/service/encryption/PasswordEncryptor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package com.dev.careers.service.encryption; | ||
|
||
import java.security.NoSuchAlgorithmException; | ||
|
||
public interface PasswordEncryptor { | ||
String makeSalt(); | ||
String hashing(byte[] password, String salt) throws NoSuchAlgorithmException; | ||
} |
43 changes: 43 additions & 0 deletions
43
src/main/java/com/dev/careers/service/encryption/SHA256Encryptor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package com.dev.careers.service.encryption; | ||
|
||
import java.security.MessageDigest; | ||
import java.security.NoSuchAlgorithmException; | ||
import java.security.SecureRandom; | ||
import org.springframework.stereotype.Component; | ||
|
||
@Component | ||
public class SHA256Encryptor implements PasswordEncryptor { | ||
private final static int SALT_SIZE = 16; | ||
|
||
@Override | ||
public String makeSalt() { | ||
SecureRandom srd = new SecureRandom(); | ||
byte[] data = new byte[SALT_SIZE]; | ||
srd.nextBytes(data); | ||
|
||
return byteArrayToString(data); | ||
} | ||
|
||
//Salt와 키 스트레칭 방식으로 구현 | ||
@Override | ||
public String hashing(byte[] password, String salt) throws NoSuchAlgorithmException { | ||
MessageDigest md = MessageDigest.getInstance("SHA-256"); | ||
|
||
StringBuilder builder = new StringBuilder(); | ||
for (int i = 0; i < 10; i++) { | ||
builder.append(byteArrayToString(password)); | ||
builder.append(salt); | ||
md.update(builder.toString().getBytes()); | ||
password = md.digest(); | ||
} | ||
return new String(password); | ||
} | ||
|
||
public String byteArrayToString(byte[] bytes) { | ||
StringBuilder builder = new StringBuilder(); | ||
for (byte data : bytes) { | ||
builder.append(String.format("%02X ", data)); | ||
} | ||
return builder.toString(); | ||
} | ||
} |
16 changes: 16 additions & 0 deletions
16
src/main/java/com/dev/careers/service/error/CuratorExceptionHandler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package com.dev.careers.service.error; | ||
|
||
import org.springframework.http.HttpStatus; | ||
import org.springframework.web.bind.annotation.ExceptionHandler; | ||
import org.springframework.web.bind.annotation.ResponseStatus; | ||
import org.springframework.web.bind.annotation.RestControllerAdvice; | ||
|
||
@RestControllerAdvice | ||
public class CuratorExceptionHandler { | ||
|
||
@ResponseStatus(HttpStatus.BAD_REQUEST) | ||
@ExceptionHandler(value = {DuplicatedEmailException.class, ViolationException.class}) | ||
public void badRequest(final RuntimeException ex) { | ||
|
||
} | ||
} |
8 changes: 8 additions & 0 deletions
8
src/main/java/com/dev/careers/service/error/DuplicatedEmailException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package com.dev.careers.service.error; | ||
|
||
public class DuplicatedEmailException extends RuntimeException { | ||
|
||
public DuplicatedEmailException() { | ||
|
||
} | ||
} |
7 changes: 7 additions & 0 deletions
7
src/main/java/com/dev/careers/service/error/ViolationException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package com.dev.careers.service.error; | ||
|
||
public class ViolationException extends RuntimeException { | ||
|
||
public ViolationException() { | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,7 @@ | ||
spring.datasource.url=jdbc:mysql://localhost:3306/<디비이름>?useUnicode=true@characterEncoding=utf8&serverTimezone=Asia/Seoul | ||
spring.datasource.username=<유저이름> | ||
spring.datasource.password=<유저비밀번호> | ||
spring.datasource.url=jdbc:mysql://localhost:3306/Careers?useUnicode=true@characterEncoding=utf8&serverTimezone=Asia/Seoul | ||
#<유저이름> | ||
spring.datasource.username=dev | ||
# <유저비밀번호> | ||
spring.datasource.password=1234 | ||
mybatis.type-aliases-package=com.dev.careers.model | ||
mybatis.mapper-locations=mybatis/*.xml |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" | ||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd"> | ||
<mapper namespace="com.dev.careers.mapper.CuratorMapper"> | ||
<select id="insertCurator" resultType="int"> | ||
INSERT INTO Curator (email, name, password, salt) | ||
VALUES (#{email}, #{name}, #{password}, #{salt}); | ||
</select> | ||
|
||
<select id="checkEmailExists" resultType="boolean"> | ||
select exists(select 1 from curator where email = #{email}); | ||
</select> | ||
</mapper> |
64 changes: 64 additions & 0 deletions
64
src/test/java/com/dev/careers/controller/CuratorControllerTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
package com.dev.careers.controller; | ||
|
||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; | ||
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; | ||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; | ||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; | ||
|
||
import com.dev.careers.service.error.CuratorExceptionHandler; | ||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.DisplayName; | ||
import org.junit.jupiter.api.Test; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.boot.test.context.SpringBootTest; | ||
import org.springframework.test.web.servlet.MockMvc; | ||
import org.springframework.test.web.servlet.setup.MockMvcBuilders; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
@SpringBootTest | ||
@Transactional | ||
class CuratorControllerTest { | ||
|
||
@Autowired | ||
CuratorController curatorController; | ||
MockMvc mockMvc; | ||
|
||
@BeforeEach | ||
public void beforeEach() { | ||
mockMvc = MockMvcBuilders.standaloneSetup(curatorController) | ||
.setControllerAdvice(new CuratorExceptionHandler()).build(); | ||
} | ||
|
||
@Test | ||
@DisplayName("정상적인 회원가입") | ||
public void joinCurator() throws Exception { | ||
mockMvc.perform(post("/curators/join") | ||
.param("email", "test@google.com") | ||
.param("name", "홍길동") | ||
.param("password", "test123!@")) | ||
.andDo(print()) | ||
.andExpect(status().isOk()); | ||
} | ||
|
||
@Test | ||
@DisplayName("잘못된 이메일 형식 요청") | ||
public void violationEmail() throws Exception { | ||
mockMvc.perform(post("/curators/join") | ||
.param("email", "test123.com") | ||
.param("name", "홍길동") | ||
.param("password", "test123!@")) | ||
.andDo(print()) | ||
.andExpect(status().isBadRequest()); | ||
} | ||
|
||
@Test | ||
@DisplayName("잘못된 비밀번호 형식 요청") | ||
public void violationPassword() throws Exception { | ||
mockMvc.perform(post("/curators/join") | ||
.param("email", "test@google.com") | ||
.param("name", "홍길동") | ||
.param("password", "123")) | ||
.andDo(print()) | ||
.andExpect(status().isBadRequest()); | ||
} | ||
} |
31 changes: 31 additions & 0 deletions
31
src/test/java/com/dev/careers/service/CuratorServiceTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package com.dev.careers.service; | ||
|
||
import com.dev.careers.model.Curator; | ||
import org.junit.jupiter.api.DisplayName; | ||
import org.junit.jupiter.api.Test; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.boot.test.context.SpringBootTest; | ||
import org.springframework.dao.DuplicateKeyException; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
@Transactional | ||
@SpringBootTest | ||
class CuratorServiceTest { | ||
|
||
@Autowired | ||
CuratorService curatorService; | ||
|
||
@Test | ||
@DisplayName("중복된 이메일 회원가입 요청") | ||
public void dupicatedEmail() throws Exception { | ||
Curator curator = new Curator( | ||
"test@google.com", | ||
"홍길동", | ||
"test123!@" | ||
); | ||
curatorService.join(curator); | ||
org.junit.jupiter.api.Assertions.assertThrows( | ||
DuplicateKeyException.class, | ||
() -> curatorService.join(curator)); | ||
} | ||
} |