-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
21 changed files
with
532 additions
and
10 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
91 changes: 91 additions & 0 deletions
91
src/main/java/com/nice/petudio/api/controller/auth/AuthController.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,91 @@ | ||
package com.nice.petudio.api.controller.auth; | ||
|
||
import com.nice.petudio.api.controller.auth.dto.request.LoginRequest; | ||
import com.nice.petudio.api.controller.auth.dto.request.SignUpRequest; | ||
import com.nice.petudio.api.controller.auth.vo.TokenVO; | ||
import com.nice.petudio.api.controller.auth.service.AuthService; | ||
import com.nice.petudio.api.controller.auth.service.AuthServiceProvider; | ||
import com.nice.petudio.api.controller.auth.service.CommonAuthService; | ||
import com.nice.petudio.api.controller.auth.service.CreateTokenService; | ||
import com.nice.petudio.api.dto.ApiResponse; | ||
import com.nice.petudio.global.auth.auth.Auth; | ||
import com.nice.petudio.global.auth.resolver.MemberId; | ||
import io.swagger.v3.oas.annotations.Operation; | ||
import jakarta.servlet.http.Cookie; | ||
import jakarta.servlet.http.HttpServletResponse; | ||
import jakarta.validation.Valid; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.http.HttpStatus; | ||
import org.springframework.web.bind.annotation.CookieValue; | ||
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.ResponseStatus; | ||
import org.springframework.web.bind.annotation.RestController; | ||
|
||
@RequiredArgsConstructor | ||
@RequestMapping("/api/v1") | ||
@RestController | ||
public class AuthController { | ||
private final AuthServiceProvider authServiceProvider; | ||
private final CreateTokenService createTokenService; | ||
private final CommonAuthService commonAuthService; | ||
|
||
|
||
@Operation(summary = "OAuth2 소셜 회원가입") | ||
@ResponseStatus(HttpStatus.OK) | ||
@PostMapping("/auth/signup") | ||
public ApiResponse<?> signUp(@Valid @RequestBody SignUpRequest request, HttpServletResponse response) { | ||
AuthService authService = authServiceProvider.getAuthService(request.getSocialType()); | ||
Long memberId = authService.signUp(request); | ||
|
||
addTokensToCookie(createTokenService.createTokenInfo(memberId), response); | ||
|
||
return ApiResponse.success(); | ||
} | ||
|
||
@Operation(summary = "OAuth2 소셜 로그인") | ||
@ResponseStatus(HttpStatus.OK) | ||
@PostMapping("/auth/login") | ||
public ApiResponse<?> login(@Valid @RequestBody LoginRequest request, HttpServletResponse response) { | ||
AuthService authService = authServiceProvider.getAuthService(request.getSocialType()); | ||
Long memberId = authService.login(request); | ||
|
||
addTokensToCookie(createTokenService.createTokenInfo(memberId), response); | ||
|
||
return ApiResponse.success(); | ||
} | ||
|
||
@Operation(summary = "[인증] 로그아웃") | ||
@Auth | ||
@ResponseStatus(HttpStatus.OK) | ||
@PostMapping("/auth/logout") | ||
public ApiResponse<String> logout(@MemberId Long memberId) { | ||
commonAuthService.logout(memberId); | ||
|
||
return ApiResponse.success(); | ||
} | ||
|
||
@Operation(summary = "JWT 토큰 갱신") | ||
@ResponseStatus(HttpStatus.OK) | ||
@PostMapping("/auth/reissue") | ||
public ApiResponse<?> reissue(@CookieValue String accessToken, @CookieValue String refreshToken, HttpServletResponse response) { | ||
TokenVO tokenVO = TokenVO.of(accessToken, refreshToken); | ||
addTokensToCookie(createTokenService.reissueToken(tokenVO), response); | ||
|
||
return ApiResponse.success(); | ||
} | ||
|
||
private void addTokensToCookie(TokenVO tokenVO, HttpServletResponse response) { | ||
addTokenToCookie("accessToken", tokenVO.getAccessToken(), response); | ||
addTokenToCookie("refreshToken", tokenVO.getRefreshToken(), response); | ||
} | ||
|
||
private void addTokenToCookie(String cookieName, String token, HttpServletResponse response) { | ||
Cookie cookie = new Cookie(cookieName, token); | ||
cookie.setSecure(true); | ||
cookie.setHttpOnly(true); | ||
|
||
response.addCookie(cookie); | ||
} | ||
} |
28 changes: 28 additions & 0 deletions
28
src/main/java/com/nice/petudio/api/controller/auth/dto/request/LoginRequest.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,28 @@ | ||
package com.nice.petudio.api.controller.auth.dto.request; | ||
|
||
|
||
import com.nice.petudio.domain.member.SocialType; | ||
import io.swagger.v3.oas.annotations.media.Schema; | ||
import jakarta.validation.constraints.NotBlank; | ||
import jakarta.validation.constraints.NotNull; | ||
import lombok.AccessLevel; | ||
import lombok.AllArgsConstructor; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
import lombok.ToString; | ||
|
||
@ToString | ||
@Getter | ||
@AllArgsConstructor(access = AccessLevel.PRIVATE) | ||
@NoArgsConstructor(access = AccessLevel.PRIVATE) | ||
public class LoginRequest { | ||
|
||
@Schema(description = "소셜 로그인 타입", example = "KAKAO") | ||
@NotNull(message = "{auth.socialType.notNull}") | ||
private SocialType socialType; | ||
|
||
@Schema(description = "소셜 토큰", example = "eyJhbGciOiJIUzUxdfadfadsMiJ9.udnKnDSK08EuX56E5k-") | ||
@NotBlank(message = "{auth.token.notBlank}") | ||
private String token; | ||
|
||
} |
33 changes: 33 additions & 0 deletions
33
src/main/java/com/nice/petudio/api/controller/auth/dto/request/SignUpRequest.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,33 @@ | ||
package com.nice.petudio.api.controller.auth.dto.request; | ||
|
||
import com.nice.petudio.api.controller.member.dto.CreateMemberRequest; | ||
import com.nice.petudio.domain.member.SocialType; | ||
import com.nice.petudio.external.client.auth.kakao.dto.response.KakaoProfileResponse; | ||
import io.swagger.v3.oas.annotations.media.Schema; | ||
import jakarta.validation.constraints.NotBlank; | ||
import jakarta.validation.constraints.NotNull; | ||
import lombok.AccessLevel; | ||
import lombok.AllArgsConstructor; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
import lombok.ToString; | ||
|
||
@ToString | ||
@Getter | ||
@AllArgsConstructor(access = AccessLevel.PRIVATE) | ||
@NoArgsConstructor(access = AccessLevel.PRIVATE) | ||
public class SignUpRequest { | ||
|
||
@Schema(description = "소셜 로그인 타입", example = "KAKAO") | ||
@NotNull(message = "{auth.socialType.notNull}") | ||
private SocialType socialType; | ||
|
||
@Schema(description = "소셜 토큰", example = "eyJhbGciOiJIUzUxdfadfadsMiJ9.udnKnDSK08EuX56E5k-") | ||
@NotBlank(message = "{auth.token.notBlank}") | ||
private String token; | ||
|
||
|
||
public CreateMemberRequest toCreateMemberDto(KakaoProfileResponse response) { | ||
return CreateMemberRequest.of(response.getId(), socialType, response.getNickname(), response.getThumbnailImage()); | ||
} | ||
} |
12 changes: 12 additions & 0 deletions
12
src/main/java/com/nice/petudio/api/controller/auth/service/AuthService.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 com.nice.petudio.api.controller.auth.service; | ||
|
||
|
||
import com.nice.petudio.api.controller.auth.dto.request.LoginRequest; | ||
import com.nice.petudio.api.controller.auth.dto.request.SignUpRequest; | ||
|
||
public interface AuthService { | ||
|
||
Long signUp(SignUpRequest request); | ||
|
||
Long login(LoginRequest request); | ||
} |
27 changes: 27 additions & 0 deletions
27
src/main/java/com/nice/petudio/api/controller/auth/service/AuthServiceProvider.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,27 @@ | ||
package com.nice.petudio.api.controller.auth.service; | ||
|
||
import com.nice.petudio.api.controller.auth.service.impl.KakaoAuthService; | ||
import com.nice.petudio.domain.member.SocialType; | ||
import jakarta.annotation.PostConstruct; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Component; | ||
|
||
@RequiredArgsConstructor | ||
@Component | ||
public class AuthServiceProvider { | ||
|
||
private static final Map<SocialType, AuthService> authServiceMap = new HashMap<>(); | ||
|
||
private final KakaoAuthService kakaoAuthService; | ||
|
||
@PostConstruct | ||
void initializeAuthServicesMap() { | ||
authServiceMap.put(SocialType.KAKAO, kakaoAuthService); | ||
} | ||
|
||
public AuthService getAuthService(SocialType socialType) { | ||
return authServiceMap.get(socialType); | ||
} | ||
} |
24 changes: 24 additions & 0 deletions
24
src/main/java/com/nice/petudio/api/controller/auth/service/CommonAuthService.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,24 @@ | ||
package com.nice.petudio.api.controller.auth.service; | ||
|
||
import com.nice.petudio.api.controller.member.service.MemberServiceUtils; | ||
import com.nice.petudio.domain.member.Member; | ||
import com.nice.petudio.domain.member.repository.MemberRepository; | ||
import com.nice.petudio.global.auth.jwt.JwtTokenService; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
@RequiredArgsConstructor | ||
@Service | ||
@Transactional | ||
public class CommonAuthService { | ||
|
||
private final MemberRepository memberRepository; | ||
|
||
private final JwtTokenService jwtTokenService; | ||
|
||
public void logout(Long memberId) { | ||
Member member = MemberServiceUtils.findMemberById(memberRepository, memberId); | ||
jwtTokenService.expireRefreshToken(member.getId()); | ||
} | ||
} |
57 changes: 57 additions & 0 deletions
57
src/main/java/com/nice/petudio/api/controller/auth/service/CreateTokenService.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,57 @@ | ||
package com.nice.petudio.api.controller.auth.service; | ||
|
||
|
||
import com.nice.petudio.api.controller.auth.vo.TokenVO; | ||
import com.nice.petudio.api.controller.member.service.MemberServiceUtils; | ||
import com.nice.petudio.domain.member.Member; | ||
import com.nice.petudio.domain.member.repository.MemberRepository; | ||
import com.nice.petudio.global.auth.jwt.JwtTokenService; | ||
import com.nice.petudio.global.config.redis.constant.RedisKey; | ||
import com.nice.petudio.global.exception.UnAuthorizedException; | ||
import com.nice.petudio.global.exception.error.ErrorCode; | ||
import java.util.List; | ||
import java.util.Objects; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.data.redis.core.RedisTemplate; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
@RequiredArgsConstructor | ||
@Service | ||
@Transactional | ||
public class CreateTokenService { | ||
|
||
private final MemberRepository memberRepository; | ||
|
||
private final RedisTemplate redisTemplate; | ||
|
||
private final JwtTokenService jwtTokenService; | ||
|
||
public TokenVO createTokenInfo(Long memberId) { | ||
List<String> tokens = jwtTokenService.createTokenInfo(memberId); | ||
return TokenVO.of(tokens.get(0), tokens.get(1)); | ||
} | ||
|
||
public TokenVO reissueToken(TokenVO tokenVO) { | ||
Long memberId = jwtTokenService.parseMemberId(tokenVO.getAccessToken()) | ||
.orElseThrow(); | ||
Member member = MemberServiceUtils.findMemberById(memberRepository, memberId); | ||
|
||
if (!jwtTokenService.validateToken(tokenVO.getRefreshToken())) { | ||
throw new UnAuthorizedException(ErrorCode.UNAUTHORIZED_JWT_EXCEPTION, | ||
String.format("MemberId(%d)의 토큰 갱신 요청에 포함된 Refresh Token이 유효하지 않아, Token Refresh가 수행되지 않았습니다.", memberId)); | ||
} | ||
String refreshToken = (String) redisTemplate.opsForValue().get(RedisKey.REFRESH_TOKEN + memberId.toString()); | ||
if (Objects.isNull(refreshToken)) { | ||
throw new UnAuthorizedException(ErrorCode.UNAUTHORIZED_JWT_EXCEPTION, | ||
String.format("보관 중인 MemberId(%d)의 Refresh Token이 존재하지 않아, Token Refresh가 수행되지 않았습니다.", memberId)); | ||
} | ||
if (!refreshToken.equals(tokenVO.getRefreshToken())) { | ||
jwtTokenService.expireRefreshToken(member.getId()); | ||
throw new UnAuthorizedException(ErrorCode.UNAUTHORIZED_JWT_EXCEPTION, | ||
String.format("보관 중인 MemberId(%d)의 Refresh Token이 유효하지 않아, Token Refresh가 수행되지 않았습니다.", memberId)); | ||
} | ||
List<String> tokens = jwtTokenService.createTokenInfo(memberId); | ||
return TokenVO.of(tokens.get(0), tokens.get(1)); | ||
} | ||
} |
41 changes: 41 additions & 0 deletions
41
src/main/java/com/nice/petudio/api/controller/auth/service/impl/KakaoAuthService.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,41 @@ | ||
package com.nice.petudio.api.controller.auth.service.impl; | ||
|
||
import com.nice.petudio.api.controller.auth.dto.request.LoginRequest; | ||
import com.nice.petudio.api.controller.auth.dto.request.SignUpRequest; | ||
import com.nice.petudio.api.controller.auth.service.AuthService; | ||
import com.nice.petudio.api.controller.member.service.MemberService; | ||
import com.nice.petudio.api.controller.member.service.MemberServiceUtils; | ||
import com.nice.petudio.domain.member.Member; | ||
import com.nice.petudio.domain.member.SocialType; | ||
import com.nice.petudio.domain.member.repository.MemberRepository; | ||
import com.nice.petudio.external.client.auth.kakao.KakaoApiCaller; | ||
import com.nice.petudio.external.client.auth.kakao.dto.response.KakaoProfileResponse; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
@RequiredArgsConstructor | ||
@Service | ||
@Transactional | ||
public class KakaoAuthService implements AuthService { | ||
|
||
private final KakaoApiCaller kakaoApiCaller; | ||
|
||
private final MemberRepository memberRepository; | ||
|
||
private final MemberService memberService; | ||
|
||
@Override | ||
public Long signUp(SignUpRequest request) { | ||
KakaoProfileResponse response = kakaoApiCaller.getProfileInfo(request.getToken()); | ||
return memberService.registerMember(request.toCreateMemberDto(response)); | ||
} | ||
|
||
@Override | ||
public Long login(LoginRequest request) { | ||
KakaoProfileResponse response = kakaoApiCaller.getProfileInfo(request.getToken()); | ||
Member member = MemberServiceUtils.findMemberBySocialIdAndSocialType(memberRepository, response.getId(), | ||
SocialType.KAKAO); | ||
return member.getId(); | ||
} | ||
} |
24 changes: 24 additions & 0 deletions
24
src/main/java/com/nice/petudio/api/controller/auth/vo/TokenVO.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,24 @@ | ||
package com.nice.petudio.api.controller.auth.vo; | ||
|
||
import lombok.AccessLevel; | ||
import lombok.AllArgsConstructor; | ||
import lombok.Builder; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Getter | ||
@NoArgsConstructor(access = AccessLevel.PRIVATE) | ||
@AllArgsConstructor(access = AccessLevel.PRIVATE) | ||
@Builder(access = AccessLevel.PRIVATE) | ||
public class TokenVO { | ||
|
||
private String accessToken; | ||
private String refreshToken; | ||
|
||
public static TokenVO of(String accessToken, String refreshToken) { | ||
return TokenVO.builder() | ||
.accessToken(accessToken) | ||
.refreshToken(refreshToken) | ||
.build(); | ||
} | ||
} |
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,33 @@ | ||
package com.nice.petudio.api.dto; | ||
|
||
import com.nice.petudio.global.exception.error.ErrorCode; | ||
import lombok.AccessLevel; | ||
import lombok.AllArgsConstructor; | ||
import lombok.Getter; | ||
import lombok.RequiredArgsConstructor; | ||
|
||
@Getter | ||
@AllArgsConstructor(access = AccessLevel.PRIVATE) | ||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE) | ||
public class ApiResponse<T> { | ||
|
||
private final boolean isSuccess; | ||
private final String code; | ||
private final String message; | ||
private T data; | ||
|
||
private static final String SUCCESS_MESSAGE = "요청이 성공적으로 수행되었습니다."; | ||
public static final String SUCCESS_CODE = "S001"; | ||
|
||
public static <T> ApiResponse<T> success(T data) { | ||
return new ApiResponse<>(true, SUCCESS_CODE, SUCCESS_MESSAGE, data); | ||
} | ||
|
||
public static <T> ApiResponse<T> success() { | ||
return new ApiResponse<>(true, SUCCESS_CODE, SUCCESS_MESSAGE); | ||
} | ||
|
||
public static <T> ApiResponse<T> error(ErrorCode errorCode) { | ||
return new ApiResponse<>(false, errorCode.getCode(), errorCode.getMessage()); | ||
} | ||
} |
Oops, something went wrong.