From 7d982063037b487abdf6fd114406950929a44e11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9B=90=EA=B7=9C?= <85729858+OneK-2@users.noreply.github.com> Date: Sat, 21 Jan 2023 20:58:52 +0900 Subject: [PATCH 01/24] Create README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..eb7e1c1 --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +# Spring-JPA-study +D-Coding 백엔드 스터디 + +1주차 과제 제출(23-01-21) From 810b9460ac37e5932ec877e8a5fe460a65cbbea2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9B=90=EA=B7=9C?= <85729858+OneK-2@users.noreply.github.com> Date: Sat, 21 Jan 2023 21:01:15 +0900 Subject: [PATCH 02/24] Create submission --- submission | 1 + 1 file changed, 1 insertion(+) create mode 100644 submission diff --git a/submission b/submission new file mode 100644 index 0000000..8695b2c --- /dev/null +++ b/submission @@ -0,0 +1 @@ +23-01-21 과제제출 From 0d6316fa2340bfe0132499a84447e82be48c8fb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9B=90=EA=B7=9C?= <85729858+OneK-2@users.noreply.github.com> Date: Sat, 21 Jan 2023 21:02:08 +0900 Subject: [PATCH 03/24] Delete submission --- submission | 1 - 1 file changed, 1 deletion(-) delete mode 100644 submission diff --git a/submission b/submission deleted file mode 100644 index 8695b2c..0000000 --- a/submission +++ /dev/null @@ -1 +0,0 @@ -23-01-21 과제제출 From 9d9d768cb557af21f0f4bc764b1213d44e6e7bed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9B=90=EA=B7=9C?= <85729858+OneK-2@users.noreply.github.com> Date: Thu, 26 Jan 2023 20:07:33 +0900 Subject: [PATCH 04/24] Update README.md --- README.md | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index eb7e1c1..1f3a19c 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,25 @@ # Spring-JPA-study D-Coding 백엔드 스터디 -1주차 과제 제출(23-01-21) +## 1주차 과제 제출(23-01-21) +스프링 입문 강의 정리 + +## 2~4주차 과제 +- 간단한 ‘당근마켓’ 벡엔드 구현해보기 +### 요구 사항 + +- 회원가입/로그인 기능 +- 상품등록 기능 +- 상품페이지 기능 +- 마이 페이지(나의 당근 페이지) 기능 + +### 제한 사항 + +- Spring 또는 Spring Boot Framework를 사용해야합니다. +- JPA를 사용해야합니다. (Spring data jpa 활용 가능) +- 인증/인가 방식은 JWT & Spring Security 를 활용해야합니다. + +### 2주차 + +- 요구사항대로 당근마켓 ERD 그려보기 +- 요구사항 API 구현 (가능한 만큼) From 6dd36f30e5c4633941e90f68819ca9c3bc0d855d Mon Sep 17 00:00:00 2001 From: OneK-2 <85729858+OneK-2@users.noreply.github.com> Date: Sat, 28 Jan 2023 10:01:57 +0900 Subject: [PATCH 05/24] =?UTF-8?q?refactor:=20=EC=8A=A4=ED=94=84=EB=A7=81?= =?UTF-8?q?=EB=B6=80=ED=8A=B8,=20=EC=9E=90=EB=B0=94=20=EB=B2=84=EC=A0=84?= =?UTF-8?q?=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 15b77ef..9fa1e35 100644 --- a/build.gradle +++ b/build.gradle @@ -1,12 +1,12 @@ plugins { id 'java' - id 'org.springframework.boot' version '3.0.1' + id 'org.springframework.boot' version '2.7.8' id 'io.spring.dependency-management' version '1.1.0' } group = 'com.dku' version = '0.0.1-SNAPSHOT' -sourceCompatibility = '17' +sourceCompatibility = '11' configurations { compileOnly { From 919d5d3152588a740909d980dafbd77c6c98cbac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9B=90=EA=B7=9C?= <85729858+OneK-2@users.noreply.github.com> Date: Sat, 28 Jan 2023 12:27:51 +0900 Subject: [PATCH 06/24] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 1f3a19c..29c13e0 100644 --- a/README.md +++ b/README.md @@ -23,3 +23,6 @@ D-Coding 백엔드 스터디 - 요구사항대로 당근마켓 ERD 그려보기 - 요구사항 API 구현 (가능한 만큼) + +![dcoding-erd](https://user-images.githubusercontent.com/85729858/215239770-a2ac0b3a-cd5b-443d-b7a3-d026ce9ae5c5.png) + From a1a16c37b6e5aee35ab99f81bb860dad566a980f Mon Sep 17 00:00:00 2001 From: OneK-2 <85729858+OneK-2@users.noreply.github.com> Date: Sun, 29 Jan 2023 16:28:23 +0900 Subject: [PATCH 07/24] =?UTF-8?q?refactor:=20yml=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/{application.properties => application.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/main/resources/{application.properties => application.yml} (100%) diff --git a/src/main/resources/application.properties b/src/main/resources/application.yml similarity index 100% rename from src/main/resources/application.properties rename to src/main/resources/application.yml From 73f98e95d67f47ef676d8f4c898027114307d9e7 Mon Sep 17 00:00:00 2001 From: OneK-2 <85729858+OneK-2@users.noreply.github.com> Date: Sun, 29 Jan 2023 23:05:58 +0900 Subject: [PATCH 08/24] =?UTF-8?q?feat:=20jwt=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/build.gradle b/build.gradle index 9fa1e35..db355ca 100644 --- a/build.gradle +++ b/build.gradle @@ -27,6 +27,13 @@ dependencies { annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.springframework.security:spring-security-test' + + runtimeOnly 'com.h2database:h2' + //implementation 'com.auth0:java-jwt:3.18.2' + // jwt + implementation 'io.jsonwebtoken:jjwt-api:0.11.5' + implementation 'io.jsonwebtoken:jjwt-impl:0.11.5' + implementation 'io.jsonwebtoken:jjwt-jackson:0.11.5' } tasks.named('test') { From d8c32ae2964fcfa3ea7eff411ead10f9c348cd1a Mon Sep 17 00:00:00 2001 From: OneK-2 <85729858+OneK-2@users.noreply.github.com> Date: Sun, 29 Jan 2023 23:06:57 +0900 Subject: [PATCH 09/24] =?UTF-8?q?feat:=20DB,=20jpa,=20jwt=EC=84=A4?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 8b13789..c822a97 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1 +1,20 @@ +spring: + datasource: + url: jdbc:h2:tcp://localhost/~/test + username: sa + password: + driver-class-name: org.h2.Driver + jpa: + hibernate: + ddl-auto: create + properties: + hibernate: + #show_sql: true + format_sql: true +logging.level: + org.hibernate.SQL: debug + org.hibernate.type: trace + +jwt: + secret: VlwEyVBsYt9V7zq57TejMnVUyzblYcfPQye08f7MGVA9XkHa From dedd7215c7491808e826edb1c765f15ec823a741 Mon Sep 17 00:00:00 2001 From: OneK-2 <85729858+OneK-2@users.noreply.github.com> Date: Sun, 29 Jan 2023 23:08:06 +0900 Subject: [PATCH 10/24] =?UTF-8?q?feat:=20erd=EB=B0=94=ED=83=95=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EC=97=94=ED=8B=B0=ED=8B=B0=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../springstudy/domain/category/Category.java | 20 ++++++++++ .../com/dku/springstudy/domain/like/like.java | 4 ++ .../springstudy/domain/product/Product.java | 33 +++++++++++++++++ .../com/dku/springstudy/domain/user/Role.java | 5 +++ .../com/dku/springstudy/domain/user/User.java | 37 +++++++++++++++++++ 5 files changed, 99 insertions(+) create mode 100644 src/main/java/com/dku/springstudy/domain/category/Category.java create mode 100644 src/main/java/com/dku/springstudy/domain/like/like.java create mode 100644 src/main/java/com/dku/springstudy/domain/product/Product.java create mode 100644 src/main/java/com/dku/springstudy/domain/user/Role.java create mode 100644 src/main/java/com/dku/springstudy/domain/user/User.java diff --git a/src/main/java/com/dku/springstudy/domain/category/Category.java b/src/main/java/com/dku/springstudy/domain/category/Category.java new file mode 100644 index 0000000..d976b4d --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/category/Category.java @@ -0,0 +1,20 @@ +package com.dku.springstudy.domain.category; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class Category { + @Id + @GeneratedValue + private Long id; + + private String categoryName; +} diff --git a/src/main/java/com/dku/springstudy/domain/like/like.java b/src/main/java/com/dku/springstudy/domain/like/like.java new file mode 100644 index 0000000..47f557b --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/like/like.java @@ -0,0 +1,4 @@ +package com.dku.springstudy.domain.like; + +public class like { +} diff --git a/src/main/java/com/dku/springstudy/domain/product/Product.java b/src/main/java/com/dku/springstudy/domain/product/Product.java new file mode 100644 index 0000000..e6466a6 --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/product/Product.java @@ -0,0 +1,33 @@ +package com.dku.springstudy.domain.product; + +import com.dku.springstudy.domain.category.Category; +import com.dku.springstudy.domain.user.User; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import javax.persistence.*; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class Product { + @Id + @GeneratedValue + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id") + private User user; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "category_id") + private Category category; + + private String productName; + private String productImgUrl; + private Integer cost; + private String contents; + + +} diff --git a/src/main/java/com/dku/springstudy/domain/user/Role.java b/src/main/java/com/dku/springstudy/domain/user/Role.java new file mode 100644 index 0000000..9f20574 --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/user/Role.java @@ -0,0 +1,5 @@ +package com.dku.springstudy.domain.user; + +public enum Role { + ROLE_USER, ROLE_ADMIN +} diff --git a/src/main/java/com/dku/springstudy/domain/user/User.java b/src/main/java/com/dku/springstudy/domain/user/User.java new file mode 100644 index 0000000..dd4ce3f --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/user/User.java @@ -0,0 +1,37 @@ +package com.dku.springstudy.domain.user; + +import com.dku.springstudy.domain.product.Product; +import lombok.*; + +import javax.persistence.*; +import java.util.ArrayList; +import java.util.List; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class User { + + @Id + @GeneratedValue + private Long id; + + @OneToMany(mappedBy = "user") + private List products = new ArrayList<>(); + + private String email; + private String password; + private String username; + private String phoneNumber; + private String nickname; + private String profileImgUrl; + + @Enumerated(EnumType.STRING) + private Role role; + + @Builder + public User(String email, String password) { + this.email = email; + this.password = password; + } +} From c6d6bdafef721a6a17b51df1633ab11802872823 Mon Sep 17 00:00:00 2001 From: OneK-2 <85729858+OneK-2@users.noreply.github.com> Date: Sun, 29 Jan 2023 23:10:41 +0900 Subject: [PATCH 11/24] =?UTF-8?q?feat:=20jwt=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../springstudy/config/SecurityConfig.java | 44 +++++++ .../springstudy/domain/user/SecurityUser.java | 76 ++++++++++++ .../user/controller/UserController.java | 26 +++++ .../domain/user/dto/LoginRequestDto.java | 9 ++ .../repository/SecurityUserRepository.java | 12 ++ .../service/CustomUserDetailsService.java | 41 +++++++ .../user/service/SecurityUserService.java | 34 ++++++ .../jwt/JwtAuthenticationFilter.java | 42 +++++++ .../dku/springstudy/jwt/JwtTokenProvider.java | 110 ++++++++++++++++++ .../com/dku/springstudy/jwt/TokenDto.java | 15 +++ 10 files changed, 409 insertions(+) create mode 100644 src/main/java/com/dku/springstudy/config/SecurityConfig.java create mode 100644 src/main/java/com/dku/springstudy/domain/user/SecurityUser.java create mode 100644 src/main/java/com/dku/springstudy/domain/user/controller/UserController.java create mode 100644 src/main/java/com/dku/springstudy/domain/user/dto/LoginRequestDto.java create mode 100644 src/main/java/com/dku/springstudy/domain/user/repository/SecurityUserRepository.java create mode 100644 src/main/java/com/dku/springstudy/domain/user/service/CustomUserDetailsService.java create mode 100644 src/main/java/com/dku/springstudy/domain/user/service/SecurityUserService.java create mode 100644 src/main/java/com/dku/springstudy/jwt/JwtAuthenticationFilter.java create mode 100644 src/main/java/com/dku/springstudy/jwt/JwtTokenProvider.java create mode 100644 src/main/java/com/dku/springstudy/jwt/TokenDto.java diff --git a/src/main/java/com/dku/springstudy/config/SecurityConfig.java b/src/main/java/com/dku/springstudy/config/SecurityConfig.java new file mode 100644 index 0000000..5614060 --- /dev/null +++ b/src/main/java/com/dku/springstudy/config/SecurityConfig.java @@ -0,0 +1,44 @@ +package com.dku.springstudy.config; + +import com.dku.springstudy.jwt.JwtAuthenticationFilter; +import com.dku.springstudy.jwt.JwtTokenProvider; +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.http.SessionCreationPolicy; + +import org.springframework.security.crypto.factory.PasswordEncoderFactories; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + + +@Configuration +@EnableWebSecurity +@RequiredArgsConstructor +public class SecurityConfig { + private final JwtTokenProvider jwtTokenProvider; + + @Bean + SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + http + .httpBasic().disable() + .csrf().disable() + .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .and() + .authorizeRequests() + .antMatchers("/api/v1/**").permitAll() + //.antMatchers("/api/v1/").hasRole("USER") + .anyRequest().authenticated() + .and() + .addFilterBefore(new JwtAuthenticationFilter(jwtTokenProvider), UsernamePasswordAuthenticationFilter.class); + return http.build(); + } + + @Bean + public PasswordEncoder passwordEncoder() { + return PasswordEncoderFactories.createDelegatingPasswordEncoder(); + } +} diff --git a/src/main/java/com/dku/springstudy/domain/user/SecurityUser.java b/src/main/java/com/dku/springstudy/domain/user/SecurityUser.java new file mode 100644 index 0000000..6f73b77 --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/user/SecurityUser.java @@ -0,0 +1,76 @@ +package com.dku.springstudy.domain.user; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; + +import javax.persistence.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + +@Getter +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Entity +public class SecurityUser implements UserDetails { + + @Id + @Column(updatable = false, unique = true, nullable = false) + private String email; + @Column(nullable = false) + private String password; + + @ElementCollection(fetch = FetchType.EAGER) + @Builder.Default + private List roles = new ArrayList<>(); + +/* public SecurityUser(User user) { + id = user.getId(); + email = user.getEmail(); + password = user.getPassword(); + }*/ + + @Override + public Collection getAuthorities() { + return this.roles.stream() + .map(SimpleGrantedAuthority::new) + .collect(Collectors.toList()); + } + + @Override + public String getUsername() { + return email; + } + + @Override + public String getPassword() { + return password; + } + + @Override + public boolean isAccountNonExpired() { + return true; + } + + @Override + public boolean isAccountNonLocked() { + return true; + } + + @Override + public boolean isCredentialsNonExpired() { + return true; + } + + @Override + public boolean isEnabled() { + return true; + } +} diff --git a/src/main/java/com/dku/springstudy/domain/user/controller/UserController.java b/src/main/java/com/dku/springstudy/domain/user/controller/UserController.java new file mode 100644 index 0000000..e1ab6ca --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/user/controller/UserController.java @@ -0,0 +1,26 @@ +package com.dku.springstudy.domain.user.controller; + + +import com.dku.springstudy.domain.user.dto.LoginRequestDto; +import com.dku.springstudy.domain.user.service.SecurityUserService; +import com.dku.springstudy.jwt.TokenDto; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/v1") +public class UserController { + private final SecurityUserService securityUserService; + + @PostMapping("/login") + public TokenDto login(@RequestBody LoginRequestDto loginRequestDto) { + String email = loginRequestDto.getEmail(); + String password = loginRequestDto.getPassword(); + TokenDto tokenDto = securityUserService.login(email, password); + return tokenDto; + } +} diff --git a/src/main/java/com/dku/springstudy/domain/user/dto/LoginRequestDto.java b/src/main/java/com/dku/springstudy/domain/user/dto/LoginRequestDto.java new file mode 100644 index 0000000..2a5b8ec --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/user/dto/LoginRequestDto.java @@ -0,0 +1,9 @@ +package com.dku.springstudy.domain.user.dto; + +import lombok.Data; + +@Data +public class LoginRequestDto { + private String email; + private String password; +} diff --git a/src/main/java/com/dku/springstudy/domain/user/repository/SecurityUserRepository.java b/src/main/java/com/dku/springstudy/domain/user/repository/SecurityUserRepository.java new file mode 100644 index 0000000..d5b6fd3 --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/user/repository/SecurityUserRepository.java @@ -0,0 +1,12 @@ +package com.dku.springstudy.domain.user.repository; + +import com.dku.springstudy.domain.user.SecurityUser; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Repository +public interface SecurityUserRepository extends JpaRepository { + Optional findByEmail(String email); +} diff --git a/src/main/java/com/dku/springstudy/domain/user/service/CustomUserDetailsService.java b/src/main/java/com/dku/springstudy/domain/user/service/CustomUserDetailsService.java new file mode 100644 index 0000000..b3cc67f --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/user/service/CustomUserDetailsService.java @@ -0,0 +1,41 @@ +package com.dku.springstudy.domain.user.service; + +import com.dku.springstudy.domain.user.SecurityUser; +import com.dku.springstudy.domain.user.repository.SecurityUserRepository; +import com.dku.springstudy.domain.user.repository.UserRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class CustomUserDetailsService implements UserDetailsService { + private final SecurityUserRepository securityUserRepository; + private final PasswordEncoder passwordEncoder; + + /*@Override + public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { + User user = userRepository.findByEmail(email) + .orElseThrow(() -> new UsernameNotFoundException("해당하는 유저를 찾을 수 없습니다.")); + return new SecurityUser(user); + }*/ + + public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { + return securityUserRepository.findByEmail(email) + .map(this::createUserDetails) + .orElseThrow(() -> new UsernameNotFoundException("해당하는 유저를 찾을 수 없습니다.")); + } + + // 해당하는 User 의 데이터가 존재한다면 UserDetails 객체로 만들어서 리턴 + private UserDetails createUserDetails(SecurityUser securityUser) { + return User.builder() + .username(securityUser.getUsername()) + .password(passwordEncoder.encode(securityUser.getPassword())) + .roles(securityUser.getRoles().toArray(new String[0])) + .build(); + } +} diff --git a/src/main/java/com/dku/springstudy/domain/user/service/SecurityUserService.java b/src/main/java/com/dku/springstudy/domain/user/service/SecurityUserService.java new file mode 100644 index 0000000..7fdef30 --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/user/service/SecurityUserService.java @@ -0,0 +1,34 @@ +package com.dku.springstudy.domain.user.service; + +import com.dku.springstudy.jwt.JwtTokenProvider; +import com.dku.springstudy.jwt.TokenDto; +import lombok.RequiredArgsConstructor; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.core.Authentication; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional(readOnly = true) +@RequiredArgsConstructor +public class SecurityUserService { + private final AuthenticationManagerBuilder authenticationManagerBuilder; + private final JwtTokenProvider jwtTokenProvider; + + @Transactional + public TokenDto login(String email, String password) { + // 1. Login ID/PW 를 기반으로 Authentication 객체 생성 + // 이때 authentication 는 인증 여부를 확인하는 authenticated 값이 false + UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(email, password); + + // 2. 실제 검증 (사용자 비밀번호 체크)이 이루어지는 부분 + // authenticate 매서드가 실행될 때 CustomUserDetailsService 에서 만든 loadUserByUsername 메서드가 실행 + Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken); + + // 3. 인증 정보를 기반으로 JWT 토큰 생성 + TokenDto tokenDto = jwtTokenProvider.generateToken(authentication); + + return tokenDto; + } +} diff --git a/src/main/java/com/dku/springstudy/jwt/JwtAuthenticationFilter.java b/src/main/java/com/dku/springstudy/jwt/JwtAuthenticationFilter.java new file mode 100644 index 0000000..9942825 --- /dev/null +++ b/src/main/java/com/dku/springstudy/jwt/JwtAuthenticationFilter.java @@ -0,0 +1,42 @@ +package com.dku.springstudy.jwt; + +import lombok.RequiredArgsConstructor; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.util.StringUtils; +import org.springframework.web.filter.GenericFilterBean; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; + +@RequiredArgsConstructor +public class JwtAuthenticationFilter extends GenericFilterBean { + private final JwtTokenProvider jwtTokenProvider; + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + + // 1. Request Header 에서 JWT 토큰 추출 + String token = resolveToken((HttpServletRequest) request); + + // 2. validateToken 으로 토큰 유효성 검사 + if (token != null && jwtTokenProvider.validateToken(token)) { + // 토큰이 유효할 경우 토큰에서 Authentication 객체를 가지고 와서 SecurityContext 에 저장 + Authentication authentication = jwtTokenProvider.getAuthentication(token); + SecurityContextHolder.getContext().setAuthentication(authentication); + } + chain.doFilter(request, response); + } + // Request Header 에서 토큰 정보 추출 + private String resolveToken(HttpServletRequest request) { + String bearerToken = request.getHeader("Authorization"); + if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer")) { + return bearerToken.substring(7); + } + return null; + } +} diff --git a/src/main/java/com/dku/springstudy/jwt/JwtTokenProvider.java b/src/main/java/com/dku/springstudy/jwt/JwtTokenProvider.java new file mode 100644 index 0000000..16f4a44 --- /dev/null +++ b/src/main/java/com/dku/springstudy/jwt/JwtTokenProvider.java @@ -0,0 +1,110 @@ +package com.dku.springstudy.jwt; + + +import io.jsonwebtoken.*; +import io.jsonwebtoken.io.Decoders; +import io.jsonwebtoken.security.Keys; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.stereotype.Component; + +import java.security.Key; +import java.util.Arrays; +import java.util.Collection; +import java.util.Date; +import java.util.stream.Collectors; + + +@Slf4j +@Component +public class JwtTokenProvider { + + private final Key key; + + public JwtTokenProvider(@Value("${jwt.secret}") String secretKey) { + byte[] keyBytes = Decoders.BASE64.decode(secretKey); + this.key = Keys.hmacShaKeyFor(keyBytes); + } + + public TokenDto generateToken(Authentication authentication) { + // 권한 가져오기 + String authorities = authentication.getAuthorities().stream() + .map(GrantedAuthority::getAuthority) + .collect(Collectors.joining(",")); + + long now = (new Date()).getTime(); + // Access Token 생성 + Date accessTokenExpiresIn = new Date(now + 86400000); + String accessToken = Jwts.builder() + .setSubject(authentication.getName()) + .claim("auth", authorities) + .setExpiration(accessTokenExpiresIn) + .signWith(key, SignatureAlgorithm.HS256) + .compact(); + + // Refresh Token 생성 + //1일: 24 * 60 * 60 * 1000 = 86400000 + String refreshToken = Jwts.builder() + .setExpiration(new Date(now + 86400000)) + .signWith(key, SignatureAlgorithm.HS256) + .compact(); + + return TokenDto.builder() + .grantType("Bearer") + .accessToken(accessToken) + .refreshToken(refreshToken) + .build(); + } + + // JWT 토큰을 복호화하여 토큰에 들어있는 정보를 꺼내는 메서드 + public Authentication getAuthentication(String accessToken) { + // 토큰 복호화 + Claims claims = parseClaims(accessToken); + + if (claims.get("auth") == null) { + throw new RuntimeException("권한 정보가 없는 토큰입니다."); + } + + // 클레임에서 권한 정보 가져오기 + Collection authorities = + Arrays.stream(claims.get("auth").toString().split(",")) + .map(SimpleGrantedAuthority::new) + .collect(Collectors.toList()); + + // UserDetails 객체를 만들어서 Authentication 리턴 + UserDetails principal = new User(claims.getSubject(), "", authorities); + return new UsernamePasswordAuthenticationToken(principal, "", authorities); + } + + // 토큰 정보를 검증하는 메서드 + public boolean validateToken(String token) { + try { + Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token); + return true; + } catch (io.jsonwebtoken.security.SecurityException | MalformedJwtException e) { + log.info("Invalid JWT Token", e); + } catch (ExpiredJwtException e) { + log.info("Expired JWT Token", e); + } catch (UnsupportedJwtException e) { + log.info("Unsupported JWT Token", e); + } catch (IllegalArgumentException e) { + log.info("JWT claims string is empty.", e); + } + return false; + } + + private Claims parseClaims(String accessToken) { + try { + return Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(accessToken).getBody(); + } catch (ExpiredJwtException e) { + return e.getClaims(); + } + } +} diff --git a/src/main/java/com/dku/springstudy/jwt/TokenDto.java b/src/main/java/com/dku/springstudy/jwt/TokenDto.java new file mode 100644 index 0000000..0737d70 --- /dev/null +++ b/src/main/java/com/dku/springstudy/jwt/TokenDto.java @@ -0,0 +1,15 @@ +package com.dku.springstudy.jwt; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; + +@Builder +@Data +@AllArgsConstructor +public class TokenDto { + //grantType은 JWT 대한 인증 타입 + private String grantType; + private String accessToken; + private String refreshToken; +} From fa545ff70e40ed085845c934a9e207befb806f41 Mon Sep 17 00:00:00 2001 From: OneK-2 <85729858+OneK-2@users.noreply.github.com> Date: Sun, 29 Jan 2023 23:12:07 +0900 Subject: [PATCH 12/24] =?UTF-8?q?feat:=20=EA=B8=B0=EB=B3=B8=20=EC=9C=A0?= =?UTF-8?q?=EC=A0=80=20=EC=84=9C=EB=B9=84=EC=8A=A4,=20=EC=BB=A8=ED=8A=B8?= =?UTF-8?q?=EB=A1=A4=EB=9F=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user/repository/UserRepository.java | 10 ++++++ .../domain/user/service/UserService.java | 36 +++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 src/main/java/com/dku/springstudy/domain/user/repository/UserRepository.java create mode 100644 src/main/java/com/dku/springstudy/domain/user/service/UserService.java diff --git a/src/main/java/com/dku/springstudy/domain/user/repository/UserRepository.java b/src/main/java/com/dku/springstudy/domain/user/repository/UserRepository.java new file mode 100644 index 0000000..0e3e396 --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/user/repository/UserRepository.java @@ -0,0 +1,10 @@ +package com.dku.springstudy.domain.user.repository; + +import com.dku.springstudy.domain.user.User; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface UserRepository extends JpaRepository { + +} diff --git a/src/main/java/com/dku/springstudy/domain/user/service/UserService.java b/src/main/java/com/dku/springstudy/domain/user/service/UserService.java new file mode 100644 index 0000000..fc84aab --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/user/service/UserService.java @@ -0,0 +1,36 @@ +package com.dku.springstudy.domain.user.service; + +import com.dku.springstudy.domain.exception.UsernameAlreadyExistException; +import com.dku.springstudy.domain.user.User; +import com.dku.springstudy.domain.user.dto.UserRequestDTO; +import com.dku.springstudy.domain.user.repository.UserRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class UserService { +/* private final UserRepository userRepository; + private final PasswordEncoder passwordEncoder; + + public void create(UserRequestDTO userRequestDTO) throws IllegalArgumentException, UsernameAlreadyExistException { + validate(userRequestDTO); + User user = userRequestDTO.toEntity(); + user.(passwordEncoder.encode(user.getPassword())); + + userRepository.save(user); + } + + private void validate(UserRequestDTO userDTO) throws IllegalArgumentException, UsernameAlreadyExistException { + if (userDTO.getUsername().isBlank() || userDTO.getPassword().isBlank()) { + throw new IllegalArgumentException(); + } + if (userRepository.findByUsername(userDTO.getUsername()).isPresent()) { + throw new UsernameAlreadyExistException(); + } + }*/ +} From 82138942ce02f43131a4a03eeb980186fd143400 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9B=90=EA=B7=9C?= <85729858+OneK-2@users.noreply.github.com> Date: Wed, 1 Feb 2023 23:34:12 +0900 Subject: [PATCH 13/24] Update README.md --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 29c13e0..82b574c 100644 --- a/README.md +++ b/README.md @@ -26,3 +26,8 @@ D-Coding 백엔드 스터디 ![dcoding-erd](https://user-images.githubusercontent.com/85729858/215239770-a2ac0b3a-cd5b-443d-b7a3-d026ce9ae5c5.png) + +### 3주차 + +- 피드백 반영하여 카테고리를 enum으로 처리하도록 하고, createdDate와 updatedDate추가 +![image](https://user-images.githubusercontent.com/85729858/216071539-42dc3af6-452e-464f-9a68-c52364c5fc3f.png) From 9de73e4f11287989a5e0f41d74cd6331529fd98b Mon Sep 17 00:00:00 2001 From: OneK-2 <85729858+OneK-2@users.noreply.github.com> Date: Sun, 5 Feb 2023 21:57:56 +0900 Subject: [PATCH 14/24] =?UTF-8?q?feat:=20=EC=83=9D=EC=84=B1=EC=8B=9C?= =?UTF-8?q?=EA=B0=84,=20=EC=88=98=EC=A0=95=EC=8B=9C=EA=B0=84=20=EB=B0=98?= =?UTF-8?q?=EC=98=81=20=EC=9C=84=ED=95=9C=20BaseTimeEntity=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../springstudy/domain/BaseTimeEntity.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/main/java/com/dku/springstudy/domain/BaseTimeEntity.java diff --git a/src/main/java/com/dku/springstudy/domain/BaseTimeEntity.java b/src/main/java/com/dku/springstudy/domain/BaseTimeEntity.java new file mode 100644 index 0000000..673b74c --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/BaseTimeEntity.java @@ -0,0 +1,23 @@ +package com.dku.springstudy.domain; + +import lombok.Getter; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import javax.persistence.Column; +import javax.persistence.EntityListeners; +import javax.persistence.MappedSuperclass; +import java.time.LocalDateTime; + +@EntityListeners(AuditingEntityListener.class) +@MappedSuperclass +@Getter +public class BaseTimeEntity { + @CreatedDate + @Column(updatable = false) + private LocalDateTime createdDate; + + @LastModifiedDate + private LocalDateTime lastModifiedDate; +} From be9261ac6b43934f982c588168e6a55d20bc2023 Mon Sep 17 00:00:00 2001 From: OneK-2 <85729858+OneK-2@users.noreply.github.com> Date: Sun, 5 Feb 2023 21:59:23 +0900 Subject: [PATCH 15/24] =?UTF-8?q?refactor:=20validation=20=EC=9C=84?= =?UTF-8?q?=ED=95=9C=20=EC=84=A4=EC=A0=95=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build.gradle b/build.gradle index db355ca..ee53417 100644 --- a/build.gradle +++ b/build.gradle @@ -34,6 +34,8 @@ dependencies { implementation 'io.jsonwebtoken:jjwt-api:0.11.5' implementation 'io.jsonwebtoken:jjwt-impl:0.11.5' implementation 'io.jsonwebtoken:jjwt-jackson:0.11.5' + + implementation 'org.springframework.boot:spring-boot-starter-validation' } tasks.named('test') { From 9f19d077538b5712f208c6c2a9f9bd4a9d3ddd5e Mon Sep 17 00:00:00 2001 From: OneK-2 <85729858+OneK-2@users.noreply.github.com> Date: Sun, 5 Feb 2023 22:00:06 +0900 Subject: [PATCH 16/24] =?UTF-8?q?refactor:=20=EC=B9=B4=ED=85=8C=EA=B3=A0?= =?UTF-8?q?=EB=A6=AC=EB=A5=BC=20enum=EC=9C=BC=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../springstudy/domain/category/Category.java | 20 ----------- .../springstudy/domain/product/Category.java | 36 +++++++++++++++++++ 2 files changed, 36 insertions(+), 20 deletions(-) delete mode 100644 src/main/java/com/dku/springstudy/domain/category/Category.java create mode 100644 src/main/java/com/dku/springstudy/domain/product/Category.java diff --git a/src/main/java/com/dku/springstudy/domain/category/Category.java b/src/main/java/com/dku/springstudy/domain/category/Category.java deleted file mode 100644 index d976b4d..0000000 --- a/src/main/java/com/dku/springstudy/domain/category/Category.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.dku.springstudy.domain.category; - -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NoArgsConstructor; - -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.Id; - -@Entity -@Getter -@NoArgsConstructor(access = AccessLevel.PROTECTED) -public class Category { - @Id - @GeneratedValue - private Long id; - - private String categoryName; -} diff --git a/src/main/java/com/dku/springstudy/domain/product/Category.java b/src/main/java/com/dku/springstudy/domain/product/Category.java new file mode 100644 index 0000000..7d1abcd --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/product/Category.java @@ -0,0 +1,36 @@ +package com.dku.springstudy.domain.product; + +import lombok.Getter; + +@Getter +public enum Category { + /* + ‘디지털기기’, ‘생활가전’, ‘가구/인테리어’, ‘유아동’, ‘생활/가공식품’, + ‘유아도서’, ‘스포츠/레저’, ‘여성잡화’, ‘여성의류’, ‘남성패션/잡화’, + ‘게임/취미’, ‘뷰티/미용’, ‘반려동물용품’, ‘도서/티켓/음반’, ‘식물’, + ‘기타 중고물품’, ‘중고차’ + */ + DIGITAL_DEVICE("디지털기기"), + HOME_ELECTRONIC("생활가전"), + FURNITURE_INTERIOR("가구/인테리어"), + CHILD("유아동"), + LIVING_PROCESSED_FOODS("생활/가공식품"), + CHILD_BOOK("유아도서"), + SPORTS_LEISURE("스포츠/레저"), + WOMAN_GOODS("여성잡화"), + WOMAN_CLOTHES("여성의류"), + MAN_FASHION_GOODS("남성패션/잡화"), + GAME_HOBBY("게임/취미"), + BEAUTY("뷰티/미용"), + PET_GOODS("반려동물용품"), + BOOK_TICKET_RECORD("도서/티켓/음반"), + PLANT("식물"), + USED_ETC("기타 중고물품"), + USED_CAR("중고차"); + + private final String korCategory; + + Category(String korCategory) { + this.korCategory = korCategory; + } +} From a2365fc8cce0ed9b255693bc2e9a69bd01faae10 Mon Sep 17 00:00:00 2001 From: OneK-2 <85729858+OneK-2@users.noreply.github.com> Date: Sun, 5 Feb 2023 22:01:09 +0900 Subject: [PATCH 17/24] =?UTF-8?q?refactor:=20role=20=EC=9D=B4=EB=A6=84=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/dku/springstudy/domain/user/Role.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/dku/springstudy/domain/user/Role.java b/src/main/java/com/dku/springstudy/domain/user/Role.java index 9f20574..a7c98a7 100644 --- a/src/main/java/com/dku/springstudy/domain/user/Role.java +++ b/src/main/java/com/dku/springstudy/domain/user/Role.java @@ -1,5 +1,5 @@ package com.dku.springstudy.domain.user; public enum Role { - ROLE_USER, ROLE_ADMIN + USER, ADMIN } From f23049c44f7e46d4e02efb755841c1e57efc4443 Mon Sep 17 00:00:00 2001 From: OneK-2 <85729858+OneK-2@users.noreply.github.com> Date: Sun, 5 Feb 2023 22:06:23 +0900 Subject: [PATCH 18/24] =?UTF-8?q?refactor:=20login=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EB=A6=AC=ED=8E=99=ED=86=A0=EB=A7=81,=20=ED=9A=8C=EC=9B=90?= =?UTF-8?q?=EA=B0=80=EC=9E=85=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../springstudy/SpringStudyApplication.java | 2 + .../springstudy/config/SecurityConfig.java | 4 +- .../springstudy/domain/user/SecurityUser.java | 76 ------------------- .../com/dku/springstudy/domain/user/User.java | 10 ++- .../user/controller/UserController.java | 21 +++-- .../domain/user/dto/SignUpRequestDTO.java | 31 ++++++++ .../repository/SecurityUserRepository.java | 12 --- .../user/repository/UserRepository.java | 6 +- .../service/CustomUserDetailsService.java | 28 ++----- .../user/service/SecurityUserService.java | 34 --------- .../domain/user/service/UserService.java | 48 +++++++----- .../springstudy/jwt/SecurityUserDetails.java | 62 +++++++++++++++ 12 files changed, 162 insertions(+), 172 deletions(-) delete mode 100644 src/main/java/com/dku/springstudy/domain/user/SecurityUser.java create mode 100644 src/main/java/com/dku/springstudy/domain/user/dto/SignUpRequestDTO.java delete mode 100644 src/main/java/com/dku/springstudy/domain/user/repository/SecurityUserRepository.java delete mode 100644 src/main/java/com/dku/springstudy/domain/user/service/SecurityUserService.java create mode 100644 src/main/java/com/dku/springstudy/jwt/SecurityUserDetails.java diff --git a/src/main/java/com/dku/springstudy/SpringStudyApplication.java b/src/main/java/com/dku/springstudy/SpringStudyApplication.java index ef164c9..1bef475 100644 --- a/src/main/java/com/dku/springstudy/SpringStudyApplication.java +++ b/src/main/java/com/dku/springstudy/SpringStudyApplication.java @@ -2,7 +2,9 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; +@EnableJpaAuditing @SpringBootApplication public class SpringStudyApplication { diff --git a/src/main/java/com/dku/springstudy/config/SecurityConfig.java b/src/main/java/com/dku/springstudy/config/SecurityConfig.java index 5614060..65e9db0 100644 --- a/src/main/java/com/dku/springstudy/config/SecurityConfig.java +++ b/src/main/java/com/dku/springstudy/config/SecurityConfig.java @@ -25,13 +25,15 @@ public class SecurityConfig { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .httpBasic().disable() + .formLogin().disable() .csrf().disable() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .authorizeRequests() .antMatchers("/api/v1/**").permitAll() //.antMatchers("/api/v1/").hasRole("USER") - .anyRequest().authenticated() + //.anyRequest().authenticated() + .anyRequest().permitAll() .and() .addFilterBefore(new JwtAuthenticationFilter(jwtTokenProvider), UsernamePasswordAuthenticationFilter.class); return http.build(); diff --git a/src/main/java/com/dku/springstudy/domain/user/SecurityUser.java b/src/main/java/com/dku/springstudy/domain/user/SecurityUser.java deleted file mode 100644 index 6f73b77..0000000 --- a/src/main/java/com/dku/springstudy/domain/user/SecurityUser.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.dku.springstudy.domain.user; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.core.userdetails.UserDetails; - -import javax.persistence.*; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.stream.Collectors; - -@Getter -@Builder -@NoArgsConstructor -@AllArgsConstructor -@Entity -public class SecurityUser implements UserDetails { - - @Id - @Column(updatable = false, unique = true, nullable = false) - private String email; - @Column(nullable = false) - private String password; - - @ElementCollection(fetch = FetchType.EAGER) - @Builder.Default - private List roles = new ArrayList<>(); - -/* public SecurityUser(User user) { - id = user.getId(); - email = user.getEmail(); - password = user.getPassword(); - }*/ - - @Override - public Collection getAuthorities() { - return this.roles.stream() - .map(SimpleGrantedAuthority::new) - .collect(Collectors.toList()); - } - - @Override - public String getUsername() { - return email; - } - - @Override - public String getPassword() { - return password; - } - - @Override - public boolean isAccountNonExpired() { - return true; - } - - @Override - public boolean isAccountNonLocked() { - return true; - } - - @Override - public boolean isCredentialsNonExpired() { - return true; - } - - @Override - public boolean isEnabled() { - return true; - } -} diff --git a/src/main/java/com/dku/springstudy/domain/user/User.java b/src/main/java/com/dku/springstudy/domain/user/User.java index dd4ce3f..0869383 100644 --- a/src/main/java/com/dku/springstudy/domain/user/User.java +++ b/src/main/java/com/dku/springstudy/domain/user/User.java @@ -1,5 +1,6 @@ package com.dku.springstudy.domain.user; +import com.dku.springstudy.domain.BaseTimeEntity; import com.dku.springstudy.domain.product.Product; import lombok.*; @@ -10,7 +11,7 @@ @Entity @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) -public class User { +public class User extends BaseTimeEntity { @Id @GeneratedValue @@ -30,8 +31,13 @@ public class User { private Role role; @Builder - public User(String email, String password) { + public User(String email, String password, String username, String phoneNumber, String nickname, String profileImgUrl) { this.email = email; this.password = password; + this.username = username; + this.phoneNumber = phoneNumber; + this.nickname = nickname; + this.profileImgUrl = profileImgUrl; + this.role = Role.USER; } } diff --git a/src/main/java/com/dku/springstudy/domain/user/controller/UserController.java b/src/main/java/com/dku/springstudy/domain/user/controller/UserController.java index e1ab6ca..538898a 100644 --- a/src/main/java/com/dku/springstudy/domain/user/controller/UserController.java +++ b/src/main/java/com/dku/springstudy/domain/user/controller/UserController.java @@ -2,25 +2,36 @@ import com.dku.springstudy.domain.user.dto.LoginRequestDto; -import com.dku.springstudy.domain.user.service.SecurityUserService; +import com.dku.springstudy.domain.user.dto.SignUpRequestDTO; +import com.dku.springstudy.domain.user.service.UserService; import com.dku.springstudy.jwt.TokenDto; import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import javax.validation.Valid; + @RestController @RequiredArgsConstructor @RequestMapping("/api/v1") public class UserController { - private final SecurityUserService securityUserService; + private final UserService userService; + + @PostMapping("/signup") + public ResponseEntity signUp(@Valid @RequestBody SignUpRequestDTO requestDTO){ + userService.signUp(requestDTO); + + return ResponseEntity.status(HttpStatus.CREATED).body(null); + } @PostMapping("/login") - public TokenDto login(@RequestBody LoginRequestDto loginRequestDto) { + public TokenDto login(@Valid @RequestBody LoginRequestDto loginRequestDto) { String email = loginRequestDto.getEmail(); String password = loginRequestDto.getPassword(); - TokenDto tokenDto = securityUserService.login(email, password); - return tokenDto; + return userService.login(email, password); } } diff --git a/src/main/java/com/dku/springstudy/domain/user/dto/SignUpRequestDTO.java b/src/main/java/com/dku/springstudy/domain/user/dto/SignUpRequestDTO.java new file mode 100644 index 0000000..78c44ba --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/user/dto/SignUpRequestDTO.java @@ -0,0 +1,31 @@ +package com.dku.springstudy.domain.user.dto; + +import com.dku.springstudy.domain.user.User; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.NonNull; + +@Data +@NoArgsConstructor +public class SignUpRequestDTO { + @NonNull + private String email; + @NonNull + private String password; + @NonNull + private String username; + @NonNull + private String phoneNumber; + @NonNull + private String nickname; + + public User toEntity() { + return User.builder() + .email(email) + .password(password) + .username(username) + .phoneNumber(phoneNumber) + .nickname(nickname) + .build(); + } +} diff --git a/src/main/java/com/dku/springstudy/domain/user/repository/SecurityUserRepository.java b/src/main/java/com/dku/springstudy/domain/user/repository/SecurityUserRepository.java deleted file mode 100644 index d5b6fd3..0000000 --- a/src/main/java/com/dku/springstudy/domain/user/repository/SecurityUserRepository.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.dku.springstudy.domain.user.repository; - -import com.dku.springstudy.domain.user.SecurityUser; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -import java.util.Optional; - -@Repository -public interface SecurityUserRepository extends JpaRepository { - Optional findByEmail(String email); -} diff --git a/src/main/java/com/dku/springstudy/domain/user/repository/UserRepository.java b/src/main/java/com/dku/springstudy/domain/user/repository/UserRepository.java index 0e3e396..304784f 100644 --- a/src/main/java/com/dku/springstudy/domain/user/repository/UserRepository.java +++ b/src/main/java/com/dku/springstudy/domain/user/repository/UserRepository.java @@ -2,9 +2,9 @@ import com.dku.springstudy.domain.user.User; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; -@Repository -public interface UserRepository extends JpaRepository { +import java.util.Optional; +public interface UserRepository extends JpaRepository { + Optional findByEmail(String email); } diff --git a/src/main/java/com/dku/springstudy/domain/user/service/CustomUserDetailsService.java b/src/main/java/com/dku/springstudy/domain/user/service/CustomUserDetailsService.java index b3cc67f..6cb7d4a 100644 --- a/src/main/java/com/dku/springstudy/domain/user/service/CustomUserDetailsService.java +++ b/src/main/java/com/dku/springstudy/domain/user/service/CustomUserDetailsService.java @@ -1,41 +1,25 @@ package com.dku.springstudy.domain.user.service; -import com.dku.springstudy.domain.user.SecurityUser; -import com.dku.springstudy.domain.user.repository.SecurityUserRepository; +import com.dku.springstudy.jwt.SecurityUserDetails; +import com.dku.springstudy.domain.user.User; + import com.dku.springstudy.domain.user.repository.UserRepository; import lombok.RequiredArgsConstructor; -import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; -import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; @Service @RequiredArgsConstructor public class CustomUserDetailsService implements UserDetailsService { - private final SecurityUserRepository securityUserRepository; - private final PasswordEncoder passwordEncoder; + private final UserRepository userRepository; - /*@Override + @Override public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { User user = userRepository.findByEmail(email) .orElseThrow(() -> new UsernameNotFoundException("해당하는 유저를 찾을 수 없습니다.")); - return new SecurityUser(user); - }*/ - - public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { - return securityUserRepository.findByEmail(email) - .map(this::createUserDetails) - .orElseThrow(() -> new UsernameNotFoundException("해당하는 유저를 찾을 수 없습니다.")); + return new SecurityUserDetails(user); } - // 해당하는 User 의 데이터가 존재한다면 UserDetails 객체로 만들어서 리턴 - private UserDetails createUserDetails(SecurityUser securityUser) { - return User.builder() - .username(securityUser.getUsername()) - .password(passwordEncoder.encode(securityUser.getPassword())) - .roles(securityUser.getRoles().toArray(new String[0])) - .build(); - } } diff --git a/src/main/java/com/dku/springstudy/domain/user/service/SecurityUserService.java b/src/main/java/com/dku/springstudy/domain/user/service/SecurityUserService.java deleted file mode 100644 index 7fdef30..0000000 --- a/src/main/java/com/dku/springstudy/domain/user/service/SecurityUserService.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.dku.springstudy.domain.user.service; - -import com.dku.springstudy.jwt.JwtTokenProvider; -import com.dku.springstudy.jwt.TokenDto; -import lombok.RequiredArgsConstructor; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; -import org.springframework.security.core.Authentication; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@Transactional(readOnly = true) -@RequiredArgsConstructor -public class SecurityUserService { - private final AuthenticationManagerBuilder authenticationManagerBuilder; - private final JwtTokenProvider jwtTokenProvider; - - @Transactional - public TokenDto login(String email, String password) { - // 1. Login ID/PW 를 기반으로 Authentication 객체 생성 - // 이때 authentication 는 인증 여부를 확인하는 authenticated 값이 false - UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(email, password); - - // 2. 실제 검증 (사용자 비밀번호 체크)이 이루어지는 부분 - // authenticate 매서드가 실행될 때 CustomUserDetailsService 에서 만든 loadUserByUsername 메서드가 실행 - Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken); - - // 3. 인증 정보를 기반으로 JWT 토큰 생성 - TokenDto tokenDto = jwtTokenProvider.generateToken(authentication); - - return tokenDto; - } -} diff --git a/src/main/java/com/dku/springstudy/domain/user/service/UserService.java b/src/main/java/com/dku/springstudy/domain/user/service/UserService.java index fc84aab..e356a85 100644 --- a/src/main/java/com/dku/springstudy/domain/user/service/UserService.java +++ b/src/main/java/com/dku/springstudy/domain/user/service/UserService.java @@ -1,36 +1,50 @@ package com.dku.springstudy.domain.user.service; -import com.dku.springstudy.domain.exception.UsernameAlreadyExistException; import com.dku.springstudy.domain.user.User; -import com.dku.springstudy.domain.user.dto.UserRequestDTO; +import com.dku.springstudy.domain.user.dto.SignUpRequestDTO; import com.dku.springstudy.domain.user.repository.UserRepository; +import com.dku.springstudy.jwt.JwtTokenProvider; +import com.dku.springstudy.jwt.TokenDto; import lombok.RequiredArgsConstructor; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.core.Authentication; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import javax.validation.Valid; @Service -@RequiredArgsConstructor @Transactional(readOnly = true) +@RequiredArgsConstructor public class UserService { -/* private final UserRepository userRepository; + private final AuthenticationManagerBuilder authenticationManagerBuilder; + private final JwtTokenProvider jwtTokenProvider; + private final UserRepository userRepository; private final PasswordEncoder passwordEncoder; + @Transactional + public TokenDto login(String email, String password) { + // 1. Login ID/PW 를 기반으로 Authentication 객체 생성 + // 이때 authentication 는 인증 여부를 확인하는 authenticated 값이 false + UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(email, password); - public void create(UserRequestDTO userRequestDTO) throws IllegalArgumentException, UsernameAlreadyExistException { - validate(userRequestDTO); - User user = userRequestDTO.toEntity(); - user.(passwordEncoder.encode(user.getPassword())); + // 2. 실제 검증 (사용자 비밀번호 체크)이 이루어지는 부분 + // authenticate 매서드가 실행될 때 CustomUserDetailsService 에서 만든 loadUserByUsername 메서드가 실행 + Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken); - userRepository.save(user); + // 3. 인증 정보를 기반으로 JWT 토큰 생성 + + return jwtTokenProvider.generateToken(authentication); } - private void validate(UserRequestDTO userDTO) throws IllegalArgumentException, UsernameAlreadyExistException { - if (userDTO.getUsername().isBlank() || userDTO.getPassword().isBlank()) { - throw new IllegalArgumentException(); - } - if (userRepository.findByUsername(userDTO.getUsername()).isPresent()) { - throw new UsernameAlreadyExistException(); - } - }*/ + @Transactional + public Long signUp(@Valid SignUpRequestDTO requestDTO){ + String bcryptPassword = passwordEncoder.encode(requestDTO.getPassword()); + requestDTO.setPassword(bcryptPassword); + User user = requestDTO.toEntity(); + userRepository.save(user); + + return user.getId(); + } } diff --git a/src/main/java/com/dku/springstudy/jwt/SecurityUserDetails.java b/src/main/java/com/dku/springstudy/jwt/SecurityUserDetails.java new file mode 100644 index 0000000..6ec4fa7 --- /dev/null +++ b/src/main/java/com/dku/springstudy/jwt/SecurityUserDetails.java @@ -0,0 +1,62 @@ +package com.dku.springstudy.jwt; + + +import com.dku.springstudy.domain.user.User; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; + +import java.util.ArrayList; +import java.util.Collection; + + +public class SecurityUserDetails implements UserDetails { + private User user; + + public SecurityUserDetails(User user) { + this.user = user; + } + + public User getUser() { + return user; + } + + @Override + public Collection getAuthorities() { + Collection authorities = new ArrayList<>(); + String roles = user.getRole().toString(); + for (String role : roles.split(",")) { + authorities.add(() -> role); + } + return authorities; + } + + @Override + public String getUsername() { + return user.getEmail(); + } + + @Override + public String getPassword() { + return user.getPassword(); + } + + @Override + public boolean isAccountNonExpired() { + return true; + } + + @Override + public boolean isAccountNonLocked() { + return true; + } + + @Override + public boolean isCredentialsNonExpired() { + return true; + } + + @Override + public boolean isEnabled() { + return true; + } +} From af99cdda94a939b8d658146e108df2ad30b330f3 Mon Sep 17 00:00:00 2001 From: OneK-2 <85729858+OneK-2@users.noreply.github.com> Date: Sun, 5 Feb 2023 22:07:48 +0900 Subject: [PATCH 19/24] =?UTF-8?q?feat:=20=EC=8B=9C=EA=B0=84=EC=84=A4?= =?UTF-8?q?=EC=A0=95=EC=B6=94=EA=B0=80,=20=EC=83=81=ED=83=9C,=20=EC=B9=B4?= =?UTF-8?q?=ED=85=8C=EA=B3=A0=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dku/springstudy/domain/product/Product.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/dku/springstudy/domain/product/Product.java b/src/main/java/com/dku/springstudy/domain/product/Product.java index e6466a6..fd9edaa 100644 --- a/src/main/java/com/dku/springstudy/domain/product/Product.java +++ b/src/main/java/com/dku/springstudy/domain/product/Product.java @@ -1,6 +1,6 @@ package com.dku.springstudy.domain.product; -import com.dku.springstudy.domain.category.Category; +import com.dku.springstudy.domain.BaseTimeEntity; import com.dku.springstudy.domain.user.User; import lombok.AccessLevel; import lombok.Getter; @@ -11,7 +11,7 @@ @Entity @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) -public class Product { +public class Product extends BaseTimeEntity { @Id @GeneratedValue private Long id; @@ -20,14 +20,16 @@ public class Product { @JoinColumn(name = "user_id") private User user; - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "category_id") - private Category category; - private String productName; private String productImgUrl; private Integer cost; private String contents; + @Enumerated(EnumType.STRING) + private ProductStatus status; + + @Enumerated(EnumType.STRING) + private Category category; + } From 98544b9e00108e790fe4746707ce3998a8e83cf7 Mon Sep 17 00:00:00 2001 From: OneK-2 <85729858+OneK-2@users.noreply.github.com> Date: Sun, 5 Feb 2023 22:08:15 +0900 Subject: [PATCH 20/24] =?UTF-8?q?feat:=20ProductRepository=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/product/repository/ProductRepository.java | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 src/main/java/com/dku/springstudy/domain/product/repository/ProductRepository.java diff --git a/src/main/java/com/dku/springstudy/domain/product/repository/ProductRepository.java b/src/main/java/com/dku/springstudy/domain/product/repository/ProductRepository.java new file mode 100644 index 0000000..fda69c6 --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/product/repository/ProductRepository.java @@ -0,0 +1,7 @@ +package com.dku.springstudy.domain.product.repository; + +import com.dku.springstudy.domain.product.Product; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ProductRepository extends JpaRepository { +} From 9e5c260d49d7c07dc82e985e7ee964c1a15f6a4f Mon Sep 17 00:00:00 2001 From: OneK-2 <85729858+OneK-2@users.noreply.github.com> Date: Sun, 5 Feb 2023 22:08:52 +0900 Subject: [PATCH 21/24] =?UTF-8?q?feat:=20ProductService=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/product/service/ProductService.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 src/main/java/com/dku/springstudy/domain/product/service/ProductService.java diff --git a/src/main/java/com/dku/springstudy/domain/product/service/ProductService.java b/src/main/java/com/dku/springstudy/domain/product/service/ProductService.java new file mode 100644 index 0000000..decbdb7 --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/product/service/ProductService.java @@ -0,0 +1,13 @@ +package com.dku.springstudy.domain.product.service; + +import com.dku.springstudy.domain.product.repository.ProductRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional(readOnly = true) +@RequiredArgsConstructor +public class ProductService { + private final ProductRepository productRepository; +} From 2fd386cab23f190623df920f6199509e292fe08f Mon Sep 17 00:00:00 2001 From: OneK-2 <85729858+OneK-2@users.noreply.github.com> Date: Sun, 5 Feb 2023 22:09:10 +0900 Subject: [PATCH 22/24] =?UTF-8?q?feat:=20ProductStatus=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../springstudy/domain/product/ProductStatus.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/main/java/com/dku/springstudy/domain/product/ProductStatus.java diff --git a/src/main/java/com/dku/springstudy/domain/product/ProductStatus.java b/src/main/java/com/dku/springstudy/domain/product/ProductStatus.java new file mode 100644 index 0000000..81dd814 --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/product/ProductStatus.java @@ -0,0 +1,15 @@ +package com.dku.springstudy.domain.product; + +import lombok.Getter; + +@Getter +public enum ProductStatus { + ON_SALE("판매중"), SOLD_OUT("판매완료"), RESERVED("예약중"); + + private final String korStatus; + + ProductStatus(String korStatus) { + this.korStatus = korStatus; + } + +} From c78c58d880976ac24015e341e744cd8c3392be7b Mon Sep 17 00:00:00 2001 From: OneK-2 <85729858+OneK-2@users.noreply.github.com> Date: Sun, 5 Feb 2023 22:10:26 +0900 Subject: [PATCH 23/24] =?UTF-8?q?feat:=20db=20=EB=8D=B0=EC=9D=B4=ED=84=B0?= =?UTF-8?q?=20=EC=A0=80=EC=9E=A5=EC=9A=A9=20=ED=81=B4=EB=9E=98=EC=8A=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/dku/springstudy/testInit.java | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 src/main/java/com/dku/springstudy/testInit.java diff --git a/src/main/java/com/dku/springstudy/testInit.java b/src/main/java/com/dku/springstudy/testInit.java new file mode 100644 index 0000000..1b44c75 --- /dev/null +++ b/src/main/java/com/dku/springstudy/testInit.java @@ -0,0 +1,56 @@ +package com.dku.springstudy; + +import com.dku.springstudy.domain.user.User; +import com.dku.springstudy.domain.user.dto.SignUpRequestDTO; +import com.dku.springstudy.domain.user.repository.UserRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.PostConstruct; +import javax.persistence.EntityManager; + +@Component +@RequiredArgsConstructor +public class testInit { + private final InitService initService; + + @PostConstruct + public void init() { + initService.dbInit1(); + + } + + @Component + @Transactional + @RequiredArgsConstructor + static class InitService { + private final UserRepository userRepository; + + private final EntityManager em; + private final PasswordEncoder passwordEncoder; + + public void dbInit1() { + + User user = createUser("qwe", "123", "username", "01012341234", "usernick"); + em.persist(user); + + } + + private User createUser(String email, String password, String username, String phoneNumber, String nickname) { + SignUpRequestDTO requestDTO = new SignUpRequestDTO(); + String bcryptPassword = passwordEncoder.encode(password); + + requestDTO.setEmail(email); + requestDTO.setPassword(bcryptPassword); + requestDTO.setUsername(username); + requestDTO.setPhoneNumber(phoneNumber); + requestDTO.setNickname(nickname); + User user = requestDTO.toEntity(); + + return user; + } + + } +} From ef784f334eb3079304db4b53e0082f9b00c47f82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9B=90=EA=B7=9C?= <85729858+OneK-2@users.noreply.github.com> Date: Sun, 5 Feb 2023 22:16:59 +0900 Subject: [PATCH 24/24] Update README.md --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 82b574c..15ac609 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,8 @@ D-Coding 백엔드 스터디 - 요구사항대로 당근마켓 ERD 그려보기 - 요구사항 API 구현 (가능한 만큼) +- jwt, security 이용하여 로그인, 회원가입 기능 구현 + ![dcoding-erd](https://user-images.githubusercontent.com/85729858/215239770-a2ac0b3a-cd5b-443d-b7a3-d026ce9ae5c5.png) @@ -30,4 +32,9 @@ D-Coding 백엔드 스터디 ### 3주차 - 피드백 반영하여 카테고리를 enum으로 처리하도록 하고, createdDate와 updatedDate추가 +- 로그인 기능 리펙토링 +- 회원가입 기능 추가 +- 상품 관련 엔티티, 레포지토리, 서비스 추가 +- 상태, 카테고리 enum추가 + ![image](https://user-images.githubusercontent.com/85729858/216071539-42dc3af6-452e-464f-9a68-c52364c5fc3f.png)