-
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.
Merge pull request #13 from MARKETFUBY/feat/member2
[차소연] 회원가입, 회원탈퇴, 로그인, 로그아웃 구현
- Loading branch information
Showing
14 changed files
with
379 additions
and
30 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
51 changes: 51 additions & 0 deletions
51
src/main/java/MARKETFUBY/Member/controller/MemberController.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,51 @@ | ||
package MARKETFUBY.Member.controller; | ||
|
||
import MARKETFUBY.Member.dto.MemberJoinRequestDto; | ||
import MARKETFUBY.Member.dto.MemberLoginRequestDto; | ||
import MARKETFUBY.Member.dto.MemberLoginResponseDto; | ||
import MARKETFUBY.Member.dto.RefreshTokenRequestDto; | ||
import MARKETFUBY.Member.service.MemberService; | ||
import MARKETFUBY.Member.service.RefreshTokenService; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.security.core.Authentication; | ||
import org.springframework.web.bind.annotation.*; | ||
|
||
@RestController | ||
@RequiredArgsConstructor | ||
@RequestMapping("/members") | ||
public class MemberController { | ||
private final MemberService memberService; | ||
private final RefreshTokenService refreshTokenService; | ||
|
||
// 회원가입 | ||
@PostMapping("/signup") | ||
public ResponseEntity<String> join (@RequestBody MemberJoinRequestDto requestDto) { | ||
return ResponseEntity.ok().body(memberService.join(requestDto.getFubyId(), requestDto.getPasswd(), requestDto.getName(), requestDto.getEmail(), requestDto.getPhone(), requestDto.getHome(), requestDto.getSex(), requestDto.getBirthday())); | ||
} | ||
|
||
// 로그인 | ||
@PostMapping("/login") | ||
public MemberLoginResponseDto login (@RequestBody MemberLoginRequestDto requestDto) { | ||
return memberService.login(requestDto.getFubyId(), requestDto.getPasswd()); | ||
} | ||
|
||
// 로그아웃 | ||
@DeleteMapping("/logout") | ||
public String logout(@RequestBody RefreshTokenRequestDto requestDto) { | ||
refreshTokenService.deleteRefreshToken(requestDto.getRefreshToken()); | ||
return "로그아웃되었습니다."; | ||
} | ||
|
||
// 회원탈퇴 | ||
@DeleteMapping("/{memberId}") | ||
public ResponseEntity<String> delete(@PathVariable Long memberId, Authentication authentication) { | ||
return ResponseEntity.ok().body(memberService.delete(memberId, authentication)); | ||
} | ||
|
||
// RefreshToken을 이용해 새로운 AccessToken을 발급받기 | ||
@PostMapping("/refreshtoken") | ||
public MemberLoginResponseDto requestRefresh (@RequestBody RefreshTokenRequestDto refreshTokenDto) { | ||
return memberService.requestRefresh(refreshTokenDto.getRefreshToken()); | ||
} | ||
} |
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,24 @@ | ||
package MARKETFUBY.Member.domain; | ||
|
||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
import lombok.Setter; | ||
|
||
import javax.persistence.*; | ||
|
||
@Entity | ||
@Getter | ||
@Setter | ||
@NoArgsConstructor | ||
public class RefreshToken { | ||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
private Long refreshTokenId; | ||
|
||
@Column(nullable = false) | ||
private Long memberId; | ||
|
||
@Column(nullable = false) | ||
private String value; | ||
} | ||
|
This file was deleted.
Oops, something went wrong.
17 changes: 17 additions & 0 deletions
17
src/main/java/MARKETFUBY/Member/dto/MemberJoinRequestDto.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,17 @@ | ||
package MARKETFUBY.Member.dto; | ||
|
||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Getter | ||
@NoArgsConstructor | ||
public class MemberJoinRequestDto { | ||
private String fubyId; | ||
private String passwd; | ||
private String name; | ||
private String email; | ||
private String phone; | ||
private String home; | ||
private String sex; | ||
private String birthday; | ||
} |
12 changes: 12 additions & 0 deletions
12
src/main/java/MARKETFUBY/Member/dto/MemberLoginRequestDto.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,12 @@ | ||
package MARKETFUBY.Member.dto; | ||
|
||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Getter | ||
@NoArgsConstructor | ||
public class MemberLoginRequestDto { | ||
private String fubyId; | ||
private String passwd; | ||
} | ||
|
23 changes: 23 additions & 0 deletions
23
src/main/java/MARKETFUBY/Member/dto/MemberLoginResponseDto.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,23 @@ | ||
package MARKETFUBY.Member.dto; | ||
|
||
import lombok.AccessLevel; | ||
import lombok.Builder; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Getter | ||
@NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
public class MemberLoginResponseDto { | ||
private Long memberId; | ||
private String username; | ||
private String accessToken; | ||
private String refreshToken; | ||
|
||
@Builder | ||
public MemberLoginResponseDto(Long memberId, String fubyId, String accessToken, String refreshToken) { | ||
this.memberId = memberId; | ||
this.username = fubyId; | ||
this.accessToken = accessToken; | ||
this.refreshToken = refreshToken; | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
src/main/java/MARKETFUBY/Member/dto/RefreshTokenRequestDto.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,11 @@ | ||
package MARKETFUBY.Member.dto; | ||
|
||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Getter | ||
@NoArgsConstructor | ||
public class RefreshTokenRequestDto { | ||
private String refreshToken; | ||
} | ||
|
8 changes: 7 additions & 1 deletion
8
src/main/java/MARKETFUBY/Member/repository/MemberRepository.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 |
---|---|---|
@@ -1,8 +1,14 @@ | ||
package MARKETFUBY.Member.repository; | ||
|
||
import MARKETFUBY.Member.domain.Member; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
import org.springframework.stereotype.Repository; | ||
|
||
import MARKETFUBY.Member.domain.Member; | ||
import java.util.Optional; | ||
|
||
@Repository | ||
public interface MemberRepository extends JpaRepository<Member, Long> { | ||
// fubyId 중복 검사 | ||
Boolean existsByFubyId(String fubyId); | ||
Optional<Member> findByFubyId(String fubyId); | ||
} |
12 changes: 12 additions & 0 deletions
12
src/main/java/MARKETFUBY/Member/repository/RefreshTokenRepository.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,12 @@ | ||
package MARKETFUBY.Member.repository; | ||
|
||
import MARKETFUBY.Member.domain.RefreshToken; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
import org.springframework.stereotype.Repository; | ||
|
||
import java.util.Optional; | ||
|
||
@Repository | ||
public interface RefreshTokenRepository extends JpaRepository<RefreshToken, Long> { | ||
Optional<RefreshToken> findByValue(String value); | ||
} |
133 changes: 133 additions & 0 deletions
133
src/main/java/MARKETFUBY/Member/service/MemberService.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,133 @@ | ||
package MARKETFUBY.Member.service; | ||
|
||
import MARKETFUBY.Member.domain.Member; | ||
import MARKETFUBY.Member.domain.RefreshToken; | ||
import MARKETFUBY.Member.domain.Sex; | ||
import MARKETFUBY.Member.dto.MemberLoginResponseDto; | ||
import MARKETFUBY.Member.repository.MemberRepository; | ||
import MARKETFUBY.utils.JwtUtil; | ||
import io.jsonwebtoken.Claims; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.security.core.Authentication; | ||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
import javax.persistence.EntityNotFoundException; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
public class MemberService { | ||
private final MemberRepository memberRepository; | ||
private final BCryptPasswordEncoder encoder; | ||
private final RefreshTokenService refreshTokenService; | ||
|
||
// AccessToken 만료 시간을 1시간으로 설정 | ||
private Long AccessExpireTimeMs = 1000 * 60 * 60L; | ||
// RefreshToken 만료 시간을 7일로 설정 | ||
private Long RefreshExpireTimeMs = 7 * 24 * 1000 * 60 * 60L; | ||
|
||
// application-secret.yml 에서 키값 가져오기 | ||
@Value("${spring.jwt.secret-key}") | ||
private String accessKey; | ||
@Value("${spring.jwt.refresh-key}") | ||
private String refreshKey; | ||
|
||
// 회원가입 | ||
public String join(String fubyId, String passwd, String name, String email, String phone, String home, String sex, String birthday) { | ||
// fubyId 중복 체크 | ||
if(existsByFubyId(fubyId)) throw new RuntimeException(fubyId + "은 이미 존재하는 아이디입니다!"); | ||
|
||
// 중복되지 않는다면 저장 | ||
memberRepository.save( | ||
Member.builder() | ||
.fubyId(fubyId) | ||
.passwd(encoder.encode(passwd)) | ||
.name(name) | ||
.email(email) | ||
.phone(phone) | ||
.home(home) | ||
.sex(Sex.valueOf(sex)) | ||
.birthday(birthday) | ||
.level("프렌즈") | ||
.build() | ||
); | ||
return "성공적으로 회원가입되었습니다!"; | ||
} | ||
|
||
@Transactional(readOnly = true) | ||
public boolean existsByFubyId(String fubyId) { | ||
return memberRepository.existsByFubyId(fubyId); | ||
} | ||
|
||
// 로그인 | ||
public MemberLoginResponseDto login(String fubyId, String passwd) { | ||
// 존재하지 않는 fubyId로 로그인을 시도하는 경우 | ||
Member foundMember = findMemberByFubyId(fubyId); | ||
|
||
// 존재하는 fubyId를 입력했지만 잘못된 비밀번호를 입력하는 경우 | ||
if(!encoder.matches(passwd, foundMember.getPasswd())) throw new RuntimeException("잘못된 비밀번호입니다."); | ||
|
||
// 로그인 성공 -> 토큰 생성 | ||
String accessToken = JwtUtil.createAccessToken(foundMember.getFubyId(), accessKey, AccessExpireTimeMs); | ||
String refreshToken = JwtUtil.createRefreshToken(foundMember.getFubyId(), refreshKey, RefreshExpireTimeMs); | ||
|
||
// RefreshToken을 DB에 저장 | ||
RefreshToken refreshTokenEntity = new RefreshToken(); | ||
refreshTokenEntity.setValue(refreshToken); | ||
refreshTokenEntity.setMemberId(foundMember.getMemberId()); | ||
refreshTokenService.addRefreshToken(refreshTokenEntity); | ||
|
||
return MemberLoginResponseDto.builder() | ||
.memberId(foundMember.getMemberId()) | ||
.fubyId(foundMember.getFubyId()) | ||
.accessToken(accessToken) | ||
.refreshToken(refreshToken) | ||
.build(); | ||
} | ||
|
||
// 회원탈퇴 | ||
public String delete(Long memberId, Authentication authentication) { | ||
Member member = findMemberById(memberId); | ||
memberRepository.delete(member); | ||
return "성공적으로 탈퇴되었습니다!"; | ||
} | ||
|
||
// fubyId로 회원 찾기 | ||
@Transactional(readOnly = true) | ||
public Member findMemberByFubyId(String fubyId) { | ||
return memberRepository.findByFubyId(fubyId) | ||
.orElseThrow(() -> new EntityNotFoundException(fubyId + "은 존재하지 않는 아이디입니다.")); | ||
} | ||
|
||
// memberId로 Member 정보 찾기 | ||
@Transactional(readOnly = true) | ||
public Member findMemberById(Long id) { | ||
return memberRepository.findById(id) | ||
.orElseThrow(() -> new EntityNotFoundException("Member ID가 " + id + "인 회원이 존재하지 않습니다.")); | ||
} | ||
|
||
// 새로운 AccessToken 발급받기 | ||
public MemberLoginResponseDto requestRefresh(String refreshToken) { | ||
// 해당 RefreshToken이 유효한지 DB에서 탐색 | ||
RefreshToken foundRefreshToken = refreshTokenService.findRefreshToken(refreshToken); | ||
// RefreshToken에 들어있는 username 값 가져오기 | ||
Claims claims = JwtUtil.parseRefreshToken(foundRefreshToken.getValue(), refreshKey); | ||
String fubyId = claims.get("username").toString(); | ||
System.out.println("Username found in RefreshToken: " + fubyId); | ||
// 가져온 fubyId에 해당하는 회원이 존재하는지 확인 | ||
Member member = findMemberByFubyId(fubyId); | ||
|
||
// 새 AccessKey 생성 | ||
String accessToken = JwtUtil.createAccessToken(member.getFubyId(), accessKey, AccessExpireTimeMs); | ||
// 새 AccessKey와 기존 RefreshKey를 DTO에 담아 리턴 | ||
return MemberLoginResponseDto | ||
.builder() | ||
.memberId(member.getMemberId()) | ||
.fubyId(member.getFubyId()) | ||
.accessToken(accessToken) | ||
.refreshToken(refreshToken) | ||
.build(); | ||
} | ||
} |
Oops, something went wrong.