Skip to content

Commit d66b38e

Browse files
[FEAT] 회원가입 로직 작성 (#20) (#47)
* [FEAT] 시큐리티 및 jwt 의종성 추가 * [FEAT] User 클래스에 Profile 연관관계 삭제 * [FEAT] 시큐리티 설정 추가 * [FEAT] CORS 설정 추가 * [FEAT] 로그인 DTO 추가 * [FEAT] 회원가입 로직 작성 * [FEAT] 회원가입, 아이디 중복 api 설정 * [REFACT] 회원가입시, 관련 엔티티 생성하는 함수의 이름 변경
1 parent 43c99eb commit d66b38e

File tree

14 files changed

+350
-12
lines changed

14 files changed

+350
-12
lines changed

build.gradle

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@ dependencies {
4747
// kafka 관련 의존성
4848
implementation 'org.springframework.kafka:spring-kafka'
4949
testImplementation 'org.springframework.kafka:spring-kafka-test'
50+
// 스프링 시큐리티
51+
implementation "org.springframework.boot:spring-boot-starter-security"
52+
//jwt 토큰
53+
implementation 'io.jsonwebtoken:jjwt-api:0.12.6'
54+
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.6'
55+
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.6'
5056
}
5157

5258
tasks.named('test') {
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.brainpix.api.code.error;
2+
3+
import org.springframework.http.HttpStatus;
4+
5+
import lombok.Getter;
6+
import lombok.RequiredArgsConstructor;
7+
8+
@Getter
9+
@RequiredArgsConstructor
10+
public enum SecurityErrorCode implements ErrorCode {
11+
IDENTIFIER_DUPLICATED(HttpStatus.BAD_REQUEST, "SECURITY400", "이미 존재하는 아이디입니다."),
12+
NICKNAME_DUPLICATED(HttpStatus.BAD_REQUEST, "SECURITY400", "이미 존재하는 닉네임입니다."),
13+
;
14+
15+
private final HttpStatus httpStatus;
16+
private final String code;
17+
private final String message;
18+
}

src/main/java/com/brainpix/profile/entity/CompanyProfile.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import java.util.List;
44

5+
import com.brainpix.user.entity.User;
6+
57
import jakarta.persistence.Entity;
68
import lombok.Builder;
79
import lombok.Getter;
@@ -17,9 +19,10 @@ public class CompanyProfile extends Profile {
1719
private Boolean openHomepage;
1820

1921
@Builder
20-
public CompanyProfile(List<Specialization> specializationList, String businessType, String businessInformation,
22+
public CompanyProfile(User user, List<Specialization> specializationList, String businessType,
23+
String businessInformation,
2124
String homepage, Boolean openHomepage) {
22-
super(specializationList);
25+
super(user, specializationList);
2326
this.businessType = businessType;
2427
this.businessInformation = businessInformation;
2528
this.homepage = homepage;

src/main/java/com/brainpix/profile/entity/IndividualProfile.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import java.util.List;
44

5+
import com.brainpix.user.entity.User;
6+
57
import jakarta.persistence.Entity;
68
import lombok.Builder;
79
import lombok.Getter;
@@ -17,9 +19,9 @@ public class IndividualProfile extends Profile {
1719
private Boolean stackOpen;
1820

1921
@Builder
20-
public IndividualProfile(List<Specialization> specializationList, String selfIntroduction, Boolean contactOpen,
21-
Boolean careerOpen, Boolean stackOpen) {
22-
super(specializationList);
22+
public IndividualProfile(User user, List<Specialization> specializationList, String selfIntroduction,
23+
Boolean contactOpen, Boolean careerOpen, Boolean stackOpen) {
24+
super(user, specializationList);
2325
this.selfIntroduction = selfIntroduction;
2426
this.ContactOpen = contactOpen;
2527
this.CareerOpen = careerOpen;

src/main/java/com/brainpix/profile/entity/Profile.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ public abstract class Profile extends BaseTimeEntity {
3737
@OneToOne(fetch = FetchType.LAZY)
3838
private User user;
3939

40-
public Profile(List<Specialization> specializationList) {
40+
public Profile(User user, List<Specialization> specializationList) {
41+
this.user = user;
4142
this.specializationList = specializationList;
4243
}
4344
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.brainpix.security;
2+
3+
import org.springframework.context.annotation.Bean;
4+
import org.springframework.context.annotation.Configuration;
5+
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
6+
import org.springframework.security.crypto.password.PasswordEncoder;
7+
8+
@Configuration
9+
public class HashEncoderConfig {
10+
11+
@Bean
12+
public PasswordEncoder passwordEncoder() {
13+
return new BCryptPasswordEncoder();
14+
}
15+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package com.brainpix.security;
2+
3+
import org.springframework.context.annotation.Bean;
4+
import org.springframework.context.annotation.Configuration;
5+
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
6+
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
7+
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
8+
import org.springframework.security.config.annotation.web.configurers.FormLoginConfigurer;
9+
import org.springframework.security.web.SecurityFilterChain;
10+
import org.springframework.web.cors.CorsConfiguration;
11+
import org.springframework.web.cors.CorsConfigurationSource;
12+
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
13+
14+
@Configuration
15+
@EnableWebSecurity
16+
public class SecurityConfig {
17+
18+
@Bean
19+
public SecurityFilterChain publicResourceConfig(HttpSecurity http) throws Exception {
20+
http.formLogin(FormLoginConfigurer::disable);
21+
http.csrf(AbstractHttpConfigurer::disable);
22+
http.cors(
23+
cors -> cors.configurationSource(corsConfigurationSource())
24+
);
25+
http.authorizeHttpRequests(
26+
(authorizeRequests)
27+
-> authorizeRequests.anyRequest().permitAll()
28+
);
29+
return http.build();
30+
}
31+
32+
public CorsConfigurationSource corsConfigurationSource() {
33+
CorsConfiguration configuration = new CorsConfiguration();
34+
35+
configuration.addAllowedOrigin("http://localhost:3000");
36+
configuration.addAllowedOrigin("https://www.brainpix.net");
37+
38+
configuration.addAllowedHeader("*");
39+
configuration.addAllowedMethod("*");
40+
41+
configuration.setAllowCredentials(true);
42+
43+
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
44+
source.registerCorsConfiguration("/**", configuration);
45+
return source;
46+
}
47+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package com.brainpix.security.controller;
2+
3+
import org.springframework.http.ResponseEntity;
4+
import org.springframework.web.bind.annotation.GetMapping;
5+
import org.springframework.web.bind.annotation.PostMapping;
6+
import org.springframework.web.bind.annotation.RequestBody;
7+
import org.springframework.web.bind.annotation.RequestMapping;
8+
import org.springframework.web.bind.annotation.RequestParam;
9+
import org.springframework.web.bind.annotation.RestController;
10+
11+
import com.brainpix.api.ApiResponse;
12+
import com.brainpix.security.dto.request.SignUpRequest;
13+
import com.brainpix.security.service.CompanySignUpService;
14+
import com.brainpix.security.service.IndividualSignUpService;
15+
16+
import lombok.RequiredArgsConstructor;
17+
18+
@RestController
19+
@RequestMapping("/users/signup")
20+
@RequiredArgsConstructor
21+
public class SignUpController {
22+
23+
private final IndividualSignUpService individualSignUpService;
24+
private final CompanySignUpService companySignUpService;
25+
26+
@PostMapping("/personal")
27+
public ResponseEntity<ApiResponse<Void>> signUpPersonal(
28+
@RequestBody SignUpRequest.PersonalSignUpRequest personalSignUpRequest) {
29+
individualSignUpService.signUpUser(personalSignUpRequest);
30+
return ResponseEntity.ok()
31+
.body(ApiResponse.createdWithNoData());
32+
}
33+
34+
@PostMapping("/company")
35+
public ResponseEntity<ApiResponse<Void>> signUpCompany(
36+
@RequestBody SignUpRequest.CompanySignUpRequest companySignUpRequest) {
37+
companySignUpService.signUpUser(companySignUpRequest);
38+
return ResponseEntity.ok()
39+
.body(ApiResponse.createdWithNoData());
40+
}
41+
42+
@GetMapping("/duplicate/id")
43+
public ResponseEntity<ApiResponse<Void>> checkDuplicateId(@RequestParam("id") String id) {
44+
individualSignUpService.isDuplicated(id);
45+
return ResponseEntity.ok()
46+
.body(ApiResponse.successWithNoData());
47+
}
48+
49+
@GetMapping("/duplicate/nickname")
50+
public ResponseEntity<ApiResponse<Void>> checkDuplicateNickName(@RequestParam("nickName") String nickName) {
51+
individualSignUpService.isDuplicatedNickName(nickName);
52+
return ResponseEntity.ok()
53+
.body(ApiResponse.successWithNoData());
54+
}
55+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package com.brainpix.security.dto.request;
2+
3+
import java.time.LocalDate;
4+
5+
import com.brainpix.user.entity.Company;
6+
import com.brainpix.user.entity.Individual;
7+
import com.brainpix.user.entity.User;
8+
9+
import lombok.Getter;
10+
import lombok.NoArgsConstructor;
11+
12+
public class SignUpRequest {
13+
14+
@Getter
15+
@NoArgsConstructor
16+
public abstract static class CommonSignUpRequest {
17+
protected String id;
18+
protected String password;
19+
protected String name;
20+
protected LocalDate birthday;
21+
protected String email;
22+
23+
public abstract User toEntity(String encodedPassword);
24+
25+
public abstract String getUserNickName();
26+
}
27+
28+
@Getter
29+
@NoArgsConstructor
30+
public static class PersonalSignUpRequest extends CommonSignUpRequest {
31+
private String nickName;
32+
33+
@Override
34+
public User toEntity(String encodedPassword) {
35+
return Individual.builder()
36+
.identifier(id)
37+
.password(encodedPassword)
38+
.name(name)
39+
.nickName(nickName)
40+
.birthday(birthday)
41+
.email(email)
42+
.profileImage("https://placehold.co/400x400")
43+
.build();
44+
}
45+
46+
@Override
47+
public String getUserNickName() {
48+
return nickName;
49+
}
50+
}
51+
52+
@Getter
53+
@NoArgsConstructor
54+
public static class CompanySignUpRequest extends CommonSignUpRequest {
55+
private String companyName;
56+
private String position;
57+
58+
@Override
59+
public User toEntity(String encodedPassword) {
60+
return Company.builder()
61+
.identifier(id)
62+
.password(encodedPassword)
63+
.name(name)
64+
.nickName(companyName)
65+
.birthday(birthday)
66+
.email(email)
67+
.position(position)
68+
.profileImage("https://placehold.co/400x400")
69+
.build();
70+
}
71+
72+
@Override
73+
public String getUserNickName() {
74+
return companyName;
75+
}
76+
}
77+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.brainpix.security.service;
2+
3+
import org.springframework.security.crypto.password.PasswordEncoder;
4+
import org.springframework.stereotype.Service;
5+
6+
import com.brainpix.profile.entity.CompanyProfile;
7+
import com.brainpix.profile.repository.ProfileRepository;
8+
import com.brainpix.user.entity.User;
9+
import com.brainpix.user.repository.UserRepository;
10+
11+
@Service
12+
public class CompanySignUpService extends SignUpService {
13+
14+
private final ProfileRepository profileRepository;
15+
16+
public CompanySignUpService(UserRepository userRepository,
17+
PasswordEncoder passwordEncoder,
18+
ProfileRepository profileRepository) {
19+
super(userRepository, passwordEncoder);
20+
this.profileRepository = profileRepository;
21+
}
22+
23+
@Override
24+
protected void firstSignupProcess(User user) {
25+
CompanyProfile profile = CompanyProfile.builder()
26+
.user(user)
27+
.specializationList(null)
28+
.businessType(null)
29+
.businessInformation(null)
30+
.homepage(null)
31+
.openHomepage(true)
32+
.build();
33+
34+
profileRepository.save(profile);
35+
}
36+
}

0 commit comments

Comments
 (0)