-
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.
Browse files
Browse the repository at this point in the history
[Feat] #26 - 소셜로그인 API 구현
- Loading branch information
Showing
53 changed files
with
907 additions
and
18 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
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
54 changes: 54 additions & 0 deletions
54
src/main/java/org/moonshot/server/domain/user/controller/UserController.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,54 @@ | ||
package org.moonshot.server.domain.user.controller; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
import org.moonshot.server.domain.user.dto.request.SocialLoginRequest; | ||
import org.moonshot.server.domain.user.dto.response.SocialLoginResponse; | ||
import org.moonshot.server.domain.user.service.UserService; | ||
import org.moonshot.server.global.auth.jwt.JwtTokenProvider; | ||
import org.moonshot.server.global.auth.jwt.TokenResponse; | ||
import org.moonshot.server.global.common.response.ApiResponse; | ||
import org.moonshot.server.global.common.response.SuccessType; | ||
import org.springframework.web.bind.annotation.*; | ||
|
||
import java.io.IOException; | ||
import java.security.Principal; | ||
|
||
@RestController | ||
@RequiredArgsConstructor | ||
@RequestMapping("/v1/user") | ||
public class UserController { | ||
|
||
private final UserService userService; | ||
|
||
@PostMapping("/login") | ||
public ApiResponse<SocialLoginResponse> login(@RequestHeader("Authorization") String authorization, | ||
@RequestBody SocialLoginRequest socialLoginRequest) throws IOException { | ||
return ApiResponse.success(SuccessType.POST_LOGIN_SUCCESS, userService.login(SocialLoginRequest.of(socialLoginRequest.socialPlatform(), authorization))); | ||
} | ||
|
||
@PostMapping("/reissue") | ||
public ApiResponse<TokenResponse> reissue(@RequestHeader("Authorization") String refreshToken) { | ||
return ApiResponse.success(SuccessType.POST_REISSUE_SUCCESS, userService.reissue(refreshToken)); | ||
} | ||
|
||
@PostMapping("/log-out") | ||
public ApiResponse<?> logout(Principal principal) { | ||
userService.logout(JwtTokenProvider.getUserIdFromPrincipal(principal)); | ||
return ApiResponse.success(SuccessType.POST_LOGOUT_SUCCESS); | ||
} | ||
|
||
@DeleteMapping("/withdrawal") | ||
public ApiResponse<?> withdrawal(Principal principal) { | ||
userService.withdrawal(JwtTokenProvider.getUserIdFromPrincipal(principal)); | ||
return ApiResponse.success(SuccessType.DELETE_USER_SUCCESS); | ||
} | ||
|
||
// @GetMapping("/login/oauth2/code/kakao") | ||
// public String kakaoSuccess(@RequestParam String code) { | ||
// return code; | ||
// } | ||
// | ||
// @GetMapping("/login/oauth2/code/google") | ||
// public String googleSuccess(@RequestParam String code, @RequestParam String scope, @RequestParam String prompt) { return code; } | ||
|
||
} |
Empty file.
12 changes: 12 additions & 0 deletions
12
src/main/java/org/moonshot/server/domain/user/dto/request/SocialLoginRequest.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 org.moonshot.server.domain.user.dto.request; | ||
|
||
import org.moonshot.server.domain.user.model.SocialPlatform; | ||
|
||
public record SocialLoginRequest( | ||
SocialPlatform socialPlatform, | ||
String code | ||
) { | ||
public static SocialLoginRequest of(SocialPlatform socialPlatform, String code) { | ||
return new SocialLoginRequest(socialPlatform, code); | ||
} | ||
} |
13 changes: 13 additions & 0 deletions
13
src/main/java/org/moonshot/server/domain/user/dto/response/SocialLoginResponse.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,13 @@ | ||
package org.moonshot.server.domain.user.dto.response; | ||
|
||
import org.moonshot.server.global.auth.jwt.TokenResponse; | ||
|
||
public record SocialLoginResponse( | ||
Long userId, | ||
String userName, | ||
TokenResponse token | ||
) { | ||
public static SocialLoginResponse of(Long userId, String userName, TokenResponse token) { | ||
return new SocialLoginResponse(userId, userName, token); | ||
} | ||
} |
20 changes: 20 additions & 0 deletions
20
src/main/java/org/moonshot/server/domain/user/dto/response/google/GoogleInfoResponse.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,20 @@ | ||
package org.moonshot.server.domain.user.dto.response.google; | ||
|
||
import com.fasterxml.jackson.databind.PropertyNamingStrategies; | ||
import com.fasterxml.jackson.databind.annotation.JsonNaming; | ||
|
||
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) | ||
public record GoogleInfoResponse( | ||
String sub, | ||
String name, | ||
String givenName, | ||
String familyName, | ||
String picture, | ||
String email, | ||
Boolean emailVerified, | ||
String locale | ||
) { | ||
public static GoogleInfoResponse of(String sub, String name, String givenName, String familyName, String picture, String email, Boolean emailVerified, String locale) { | ||
return new GoogleInfoResponse(sub, name, givenName, familyName, picture, email, emailVerified, locale); | ||
} | ||
} |
14 changes: 14 additions & 0 deletions
14
src/main/java/org/moonshot/server/domain/user/dto/response/google/GoogleTokenResponse.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,14 @@ | ||
package org.moonshot.server.domain.user.dto.response.google; | ||
|
||
import com.fasterxml.jackson.databind.PropertyNamingStrategies; | ||
import com.fasterxml.jackson.databind.annotation.JsonNaming; | ||
|
||
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) | ||
public record GoogleTokenResponse( | ||
String accessToken, | ||
String refreshToken | ||
) { | ||
public static GoogleTokenResponse of(String accessToken, String refreshToken) { | ||
return new GoogleTokenResponse(accessToken, refreshToken); | ||
} | ||
} |
10 changes: 10 additions & 0 deletions
10
src/main/java/org/moonshot/server/domain/user/dto/response/kakao/KakaoAccount.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,10 @@ | ||
package org.moonshot.server.domain.user.dto.response.kakao; | ||
|
||
import com.fasterxml.jackson.databind.PropertyNamingStrategies; | ||
import com.fasterxml.jackson.databind.annotation.JsonNaming; | ||
|
||
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) | ||
public record KakaoAccount( | ||
KakaoUserProfile profile | ||
) { | ||
} |
14 changes: 14 additions & 0 deletions
14
src/main/java/org/moonshot/server/domain/user/dto/response/kakao/KakaoTokenResponse.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,14 @@ | ||
package org.moonshot.server.domain.user.dto.response.kakao; | ||
|
||
import com.fasterxml.jackson.databind.PropertyNamingStrategies; | ||
import com.fasterxml.jackson.databind.annotation.JsonNaming; | ||
|
||
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) | ||
public record KakaoTokenResponse( | ||
String accessToken, | ||
String refreshToken | ||
) { | ||
public static KakaoTokenResponse of(String accessToken, String refreshToken) { | ||
return new KakaoTokenResponse(accessToken, refreshToken); | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
src/main/java/org/moonshot/server/domain/user/dto/response/kakao/KakaoUserProfile.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 org.moonshot.server.domain.user.dto.response.kakao; | ||
|
||
import com.fasterxml.jackson.databind.PropertyNamingStrategies; | ||
import com.fasterxml.jackson.databind.annotation.JsonNaming; | ||
|
||
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) | ||
public record KakaoUserProfile( | ||
String nickname, | ||
String profileImageUrl | ||
) { | ||
} |
11 changes: 11 additions & 0 deletions
11
src/main/java/org/moonshot/server/domain/user/dto/response/kakao/KakaoUserResponse.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 org.moonshot.server.domain.user.dto.response.kakao; | ||
|
||
import com.fasterxml.jackson.databind.PropertyNamingStrategies; | ||
import com.fasterxml.jackson.databind.annotation.JsonNaming; | ||
|
||
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) | ||
public record KakaoUserResponse( | ||
String id, | ||
KakaoAccount kakaoAccount | ||
) { | ||
} |
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
5 changes: 4 additions & 1 deletion
5
src/main/java/org/moonshot/server/domain/user/repository/UserRepository.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,11 +1,14 @@ | ||
package org.moonshot.server.domain.user.repository; | ||
|
||
import java.util.Optional; | ||
import org.moonshot.server.domain.user.model.User; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
|
||
import java.util.Optional; | ||
|
||
public interface UserRepository extends JpaRepository<User, Long> { | ||
|
||
Optional<User> findUserBySocialId(String socialId); | ||
Optional<User> findUserByNickname(String nickname); | ||
|
||
} | ||
|
153 changes: 153 additions & 0 deletions
153
src/main/java/org/moonshot/server/domain/user/service/UserService.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,153 @@ | ||
package org.moonshot.server.domain.user.service; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
import org.moonshot.server.domain.user.dto.request.SocialLoginRequest; | ||
import org.moonshot.server.domain.user.dto.response.SocialLoginResponse; | ||
import org.moonshot.server.domain.user.dto.response.google.GoogleInfoResponse; | ||
import org.moonshot.server.domain.user.dto.response.google.GoogleTokenResponse; | ||
import org.moonshot.server.domain.user.dto.response.kakao.KakaoTokenResponse; | ||
import org.moonshot.server.domain.user.dto.response.kakao.KakaoUserResponse; | ||
import org.moonshot.server.domain.user.exception.UserNotFoundException; | ||
import org.moonshot.server.domain.user.model.SocialPlatform; | ||
import org.moonshot.server.domain.user.model.User; | ||
import org.moonshot.server.domain.user.repository.UserRepository; | ||
import org.moonshot.server.global.auth.feign.google.GoogleApiClient; | ||
import org.moonshot.server.global.auth.feign.google.GoogleAuthApiClient; | ||
import org.moonshot.server.global.auth.feign.kakao.KakaoApiClient; | ||
import org.moonshot.server.global.auth.feign.kakao.KakaoAuthApiClient; | ||
import org.moonshot.server.global.auth.jwt.JwtTokenProvider; | ||
import org.moonshot.server.global.auth.jwt.TokenResponse; | ||
import org.moonshot.server.global.auth.security.UserAuthentication; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
import java.io.IOException; | ||
import java.util.Optional; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
@Transactional(readOnly = true) | ||
public class UserService { | ||
|
||
@Value("${google.client-id}") | ||
private String googleClientId; | ||
|
||
@Value("${google.client-secret}") | ||
private String googleClientSecret; | ||
|
||
@Value("${google.redirect-url}") | ||
private String googleRedirectUrl; | ||
|
||
@Value("${kakao.client-id}") | ||
private String kakaoClientId; | ||
|
||
@Value("${kakao.redirect-url}") | ||
private String kakaoRedirectUrl; | ||
|
||
private final UserRepository userRepository; | ||
private final GoogleAuthApiClient googleAuthApiClient; | ||
private final GoogleApiClient googleApiClient; | ||
private final KakaoAuthApiClient kakaoAuthApiClient; | ||
private final KakaoApiClient kakaoApiClient; | ||
private final JwtTokenProvider jwtTokenProvider; | ||
|
||
@Transactional | ||
public SocialLoginResponse login(SocialLoginRequest request) throws IOException { | ||
switch (request.socialPlatform().getValue()){ | ||
case "google": | ||
return gooleLogin(request); | ||
case "kakao": | ||
return kakaoLogin(request); | ||
} | ||
return null; | ||
} | ||
|
||
@Transactional | ||
public SocialLoginResponse gooleLogin(SocialLoginRequest request) throws IOException { | ||
GoogleTokenResponse tokenResponse = googleAuthApiClient.googleAuth( | ||
request.code(), | ||
googleClientId, | ||
googleClientSecret, | ||
googleRedirectUrl, | ||
"authorization_code" | ||
); | ||
GoogleInfoResponse userResponse = googleApiClient.googleInfo("Bearer " + tokenResponse.accessToken()); | ||
Optional<User> findUser = userRepository.findUserBySocialId(userResponse.sub()); | ||
User user; | ||
if (findUser.isEmpty()) { | ||
User newUser = userRepository.save(User.builderWithSignIn() | ||
.socialId(userResponse.sub()) | ||
.socialPlatform(request.socialPlatform()) | ||
.name(userResponse.name()) | ||
.profileImage(userResponse.picture()) | ||
.email(userResponse.email()) | ||
.build()); | ||
|
||
user = newUser; | ||
} else { | ||
user = findUser.get(); | ||
if (user.getSocialPlatform().equals(SocialPlatform.WITHDRAWAL)) { | ||
user.modifySocialPlatform(SocialPlatform.GOOGLE); | ||
} | ||
} | ||
UserAuthentication userAuthentication = new UserAuthentication(user.getId(), null, null); | ||
TokenResponse token = new TokenResponse(jwtTokenProvider.generateAccessToken(userAuthentication), jwtTokenProvider.generateRefreshToken(userAuthentication)); | ||
return SocialLoginResponse.of(user.getId(), user.getName(), token); | ||
} | ||
|
||
@Transactional | ||
public SocialLoginResponse kakaoLogin(SocialLoginRequest request) throws IOException { | ||
KakaoTokenResponse tokenResponse = kakaoAuthApiClient.getOAuth2AccessToken( | ||
"authorization_code", | ||
kakaoClientId, | ||
kakaoRedirectUrl, | ||
request.code() | ||
); | ||
KakaoUserResponse userResponse = kakaoApiClient.getUserInformation( | ||
"Bearer " + tokenResponse.accessToken()); | ||
Optional<User> findUser = userRepository.findUserBySocialId(userResponse.id()); | ||
User user; | ||
if (findUser.isEmpty()) { | ||
User newUser = userRepository.save(User.builderWithSignIn() | ||
.socialId(userResponse.id()) | ||
.socialPlatform(request.socialPlatform()) | ||
.name(userResponse.kakaoAccount().profile().nickname()) | ||
.profileImage(userResponse.kakaoAccount().profile().profileImageUrl()) | ||
.email("") | ||
.build()); | ||
|
||
user = newUser; | ||
} else { | ||
user = findUser.get(); | ||
if (user.getSocialPlatform().equals(SocialPlatform.WITHDRAWAL)) { | ||
user.modifySocialPlatform(SocialPlatform.KAKAO); | ||
} | ||
} | ||
UserAuthentication userAuthentication = new UserAuthentication(user.getId(), null, null); | ||
TokenResponse token = new TokenResponse(jwtTokenProvider.generateAccessToken(userAuthentication), jwtTokenProvider.generateRefreshToken(userAuthentication)); | ||
return SocialLoginResponse.of(user.getId(), user.getName(), token); | ||
} | ||
|
||
@Transactional | ||
public TokenResponse reissue(String refreshToken) { | ||
String token = refreshToken.substring("Bearer ".length()); | ||
Long userId = jwtTokenProvider.validateRefreshToken(token); | ||
jwtTokenProvider.deleteRefreshToken(userId); | ||
UserAuthentication userAuthentication = new UserAuthentication(userId, null, null); | ||
return jwtTokenProvider.reissuedToken(userAuthentication); | ||
} | ||
|
||
@Transactional | ||
public void logout(Long userId) { | ||
jwtTokenProvider.deleteRefreshToken(userId); | ||
} | ||
|
||
@Transactional | ||
public void withdrawal(Long userId) { | ||
User user = userRepository.findById(userId) | ||
.orElseThrow(UserNotFoundException::new); | ||
user.modifySocialPlatform(SocialPlatform.WITHDRAWAL); | ||
} | ||
|
||
} |
Empty file.
Oops, something went wrong.