-
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.
Browse files
Browse the repository at this point in the history
…o-api [FEAT] 카카오 소셜 로그인 + JWT 인증
- Loading branch information
Showing
22 changed files
with
574 additions
and
21 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
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
53 changes: 53 additions & 0 deletions
53
.../src/main/java/com/example/growthookserver/api/member/auth/controller/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,53 @@ | ||
package com.example.growthookserver.api.member.auth.controller; | ||
|
||
import com.example.growthookserver.api.member.auth.dto.Request.AuthRequestDto; | ||
import com.example.growthookserver.api.member.auth.dto.Response.AuthResponseDto; | ||
import com.example.growthookserver.api.member.auth.dto.Response.AuthTokenResponseDto; | ||
import com.example.growthookserver.api.member.auth.service.AuthService; | ||
import com.example.growthookserver.common.config.jwt.JwtTokenProvider; | ||
import com.example.growthookserver.common.response.ApiResponse; | ||
import com.example.growthookserver.common.response.SuccessStatus; | ||
import io.swagger.v3.oas.annotations.Operation; | ||
import io.swagger.v3.oas.annotations.tags.Tag; | ||
import jakarta.servlet.http.HttpServletRequest; | ||
import java.security.NoSuchAlgorithmException; | ||
import java.security.spec.InvalidKeySpecException; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.http.HttpStatus; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.PostMapping; | ||
import org.springframework.web.bind.annotation.RequestBody; | ||
import org.springframework.web.bind.annotation.RequestHeader; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.ResponseStatus; | ||
import org.springframework.web.bind.annotation.RestController; | ||
|
||
@RestController | ||
@RequestMapping("/api/v1/auth") | ||
@RequiredArgsConstructor | ||
@Tag(name = "Auth - 인증/인가 관련 API", description = "Auth API Document") | ||
public class AuthController { | ||
private final AuthService authService; | ||
private final JwtTokenProvider jwtTokenProvider; | ||
|
||
@PostMapping() | ||
@ResponseStatus(HttpStatus.OK) | ||
@Operation(summary = "SocialLogin", description = "소셜 로그인 API입니다.") | ||
public ApiResponse<AuthResponseDto> socialLogin(@RequestBody AuthRequestDto authRequestDto) throws NoSuchAlgorithmException, InvalidKeySpecException { | ||
|
||
AuthResponseDto responseDto = authService.socialLogin(authRequestDto); | ||
return ApiResponse.success(SuccessStatus.SIGNIN_SUCCESS, responseDto); | ||
|
||
} | ||
|
||
@GetMapping("/token") | ||
@ResponseStatus(HttpStatus.OK) | ||
@Operation(summary = "TokenRefresh", description = "토큰 재발급 API입니다.") | ||
public ApiResponse<AuthTokenResponseDto> getNewToken(HttpServletRequest request) { | ||
String accessToken = (String) request.getAttribute("newAccessToken"); | ||
String refreshToken = jwtTokenProvider.resolveRefreshToken(request); | ||
|
||
return ApiResponse.success(SuccessStatus.GET_NEW_TOKEN_SUCCESS, authService.getNewToken(accessToken, refreshToken)); | ||
} | ||
} |
13 changes: 13 additions & 0 deletions
13
...src/main/java/com/example/growthookserver/api/member/auth/dto/Request/AuthRequestDto.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 com.example.growthookserver.api.member.auth.dto.Request; | ||
|
||
import static lombok.AccessLevel.PROTECTED; | ||
|
||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Getter | ||
@NoArgsConstructor(access = PROTECTED) | ||
public class AuthRequestDto { | ||
private String socialPlatform; | ||
private String socialToken; | ||
} |
20 changes: 20 additions & 0 deletions
20
...c/main/java/com/example/growthookserver/api/member/auth/dto/Response/AuthResponseDto.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 com.example.growthookserver.api.member.auth.dto.Response; | ||
|
||
import lombok.AllArgsConstructor; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Getter | ||
@NoArgsConstructor | ||
@AllArgsConstructor(staticName = "of") | ||
public class AuthResponseDto { | ||
|
||
private String nickname; | ||
|
||
private Long memberId; | ||
|
||
private String accessToken; | ||
|
||
private String refreshToken; | ||
|
||
} |
14 changes: 14 additions & 0 deletions
14
...n/java/com/example/growthookserver/api/member/auth/dto/Response/AuthTokenResponseDto.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 com.example.growthookserver.api.member.auth.dto.Response; | ||
|
||
import lombok.AllArgsConstructor; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Getter | ||
@NoArgsConstructor | ||
@AllArgsConstructor(staticName = "of") | ||
public class AuthTokenResponseDto { | ||
private String accessToken; | ||
|
||
private String refreshToken; | ||
} |
13 changes: 13 additions & 0 deletions
13
...okServer/src/main/java/com/example/growthookserver/api/member/auth/dto/SocialInfoDto.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 com.example.growthookserver.api.member.auth.dto; | ||
|
||
import lombok.AllArgsConstructor; | ||
import lombok.Getter; | ||
|
||
@Getter | ||
@AllArgsConstructor | ||
public class SocialInfoDto { | ||
private String id; | ||
private String nickname; | ||
private String email; | ||
private String profileImage; | ||
} |
13 changes: 13 additions & 0 deletions
13
...Server/src/main/java/com/example/growthookserver/api/member/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,13 @@ | ||
package com.example.growthookserver.api.member.auth.service; | ||
|
||
import com.example.growthookserver.api.member.auth.dto.Request.AuthRequestDto; | ||
import com.example.growthookserver.api.member.auth.dto.Response.AuthResponseDto; | ||
import com.example.growthookserver.api.member.auth.dto.Response.AuthTokenResponseDto; | ||
import java.security.NoSuchAlgorithmException; | ||
import java.security.spec.InvalidKeySpecException; | ||
|
||
public interface AuthService { | ||
AuthResponseDto socialLogin(AuthRequestDto authRequestDto) throws NoSuchAlgorithmException, InvalidKeySpecException; | ||
|
||
AuthTokenResponseDto getNewToken(String accessToken, String refreshToken); | ||
} |
95 changes: 95 additions & 0 deletions
95
...c/main/java/com/example/growthookserver/api/member/auth/service/Impl/AuthServiceImpl.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,95 @@ | ||
package com.example.growthookserver.api.member.auth.service.Impl; | ||
|
||
import com.example.growthookserver.api.member.auth.SocialPlatform; | ||
import com.example.growthookserver.api.member.auth.dto.Request.AuthRequestDto; | ||
import com.example.growthookserver.api.member.auth.dto.Response.AuthResponseDto; | ||
import com.example.growthookserver.api.member.auth.dto.Response.AuthTokenResponseDto; | ||
|
||
import com.example.growthookserver.api.member.auth.dto.SocialInfoDto; | ||
import com.example.growthookserver.api.member.auth.service.AuthService; | ||
import com.example.growthookserver.api.member.auth.service.KakaoAuthService; | ||
|
||
import com.example.growthookserver.api.member.domain.Member; | ||
import com.example.growthookserver.api.member.repository.MemberRepository; | ||
import com.example.growthookserver.common.config.jwt.JwtTokenProvider; | ||
import com.example.growthookserver.common.config.jwt.UserAuthentication; | ||
import com.example.growthookserver.common.exception.BadRequestException; | ||
import com.example.growthookserver.common.response.ErrorStatus; | ||
import java.security.NoSuchAlgorithmException; | ||
import java.security.spec.InvalidKeySpecException; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.security.core.Authentication; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
public class AuthServiceImpl implements AuthService { | ||
private final JwtTokenProvider jwtTokenProvider; | ||
private final KakaoAuthService kakaoAuthService; | ||
private final MemberRepository memberRepository; | ||
|
||
@Override | ||
@Transactional | ||
public AuthResponseDto socialLogin(AuthRequestDto authRequestDto) throws NoSuchAlgorithmException, InvalidKeySpecException { | ||
|
||
if (authRequestDto.getSocialPlatform() == null || authRequestDto.getSocialToken() == null) { | ||
throw new BadRequestException(ErrorStatus.VALIDATION_REQUEST_MISSING_EXCEPTION.getMessage()); | ||
} | ||
|
||
try { | ||
SocialPlatform socialPlatform = SocialPlatform.valueOf(authRequestDto.getSocialPlatform()); | ||
|
||
SocialInfoDto socialData = getSocialData(socialPlatform, authRequestDto.getSocialToken()); | ||
|
||
String refreshToken = jwtTokenProvider.generateRefreshToken(); | ||
|
||
Boolean isExistUser = memberRepository.existsBySocialId(socialData.getId()); | ||
|
||
// 신규 유저 저장 | ||
if (!isExistUser.booleanValue()) { | ||
Member member = Member.builder() | ||
.nickname(socialData.getNickname()) | ||
.email(socialData.getEmail()) | ||
.socialPlatform(socialPlatform) | ||
.socialId(socialData.getId()) | ||
.profileImage(socialData.getProfileImage()) | ||
.build(); | ||
|
||
memberRepository.save(member); | ||
|
||
member.updateRefreshToken(refreshToken); | ||
} | ||
else memberRepository.findMemberBySocialIdOrThrow(socialData.getId()).updateRefreshToken(refreshToken); | ||
|
||
// socialId를 통해서 등록된 유저 찾기 | ||
Member signedMember = memberRepository.findMemberBySocialIdOrThrow(socialData.getId()); | ||
|
||
Authentication authentication = new UserAuthentication(signedMember.getId(), null, null); | ||
|
||
String accessToken = jwtTokenProvider.generateAccessToken(authentication); | ||
|
||
return AuthResponseDto.of(signedMember.getNickname(), signedMember.getId(), accessToken, signedMember.getRefreshToken()); | ||
|
||
} catch (IllegalArgumentException ex) { | ||
throw new IllegalArgumentException(ErrorStatus.ANOTHER_ACCESS_TOKEN.getMessage()); | ||
} | ||
} | ||
|
||
@Override | ||
@Transactional | ||
public AuthTokenResponseDto getNewToken(String accessToken, String refreshToken) { | ||
return AuthTokenResponseDto.of(accessToken,refreshToken); | ||
} | ||
|
||
private SocialInfoDto getSocialData(SocialPlatform socialPlatform, String socialAccessToken) throws NoSuchAlgorithmException, InvalidKeySpecException { | ||
|
||
switch (socialPlatform) { | ||
case KAKAO: | ||
return kakaoAuthService.login(socialAccessToken); | ||
default: | ||
throw new IllegalArgumentException(ErrorStatus.ANOTHER_ACCESS_TOKEN.getMessage()); | ||
} | ||
} | ||
} |
55 changes: 55 additions & 0 deletions
55
...r/src/main/java/com/example/growthookserver/api/member/auth/service/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,55 @@ | ||
package com.example.growthookserver.api.member.auth.service; | ||
|
||
import com.example.growthookserver.api.member.auth.dto.SocialInfoDto; | ||
import com.example.growthookserver.common.exception.BaseException; | ||
import com.fasterxml.jackson.core.JsonProcessingException; | ||
import com.fasterxml.jackson.databind.JsonNode; | ||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.http.HttpEntity; | ||
import org.springframework.http.HttpHeaders; | ||
import org.springframework.http.HttpStatus; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.stereotype.Component; | ||
import org.springframework.web.client.RestTemplate; | ||
|
||
@RequiredArgsConstructor | ||
@Component | ||
public class KakaoAuthService { | ||
|
||
//이 login은 카카오 서버에 AccessToken으로 접속할때의 login | ||
public SocialInfoDto login(String socialAccessToken) { | ||
return getKakaoSocialData(socialAccessToken); | ||
} | ||
|
||
private SocialInfoDto getKakaoSocialData(String socialAccessToken) { | ||
|
||
try{ | ||
RestTemplate restTemplate = new RestTemplate(); | ||
HttpHeaders headers = new HttpHeaders(); | ||
headers.add("Authorization", socialAccessToken); | ||
HttpEntity<JsonNode> httpEntity = new HttpEntity<>(headers); | ||
ResponseEntity<String> responseData = restTemplate.postForEntity("https://kapi.kakao.com/v2/user/me", httpEntity, String.class); | ||
ObjectMapper objectMapper = new ObjectMapper(); | ||
|
||
JsonNode jsonNode = objectMapper.readTree(responseData.getBody()); | ||
|
||
String nickname = jsonNode.get("kakao_account").get("profile").get("nickname").asText(); | ||
String profileImage; | ||
try { | ||
profileImage = jsonNode.get("kakao_account").get("profile").get("profile_image_url").asText(); | ||
} catch (NullPointerException e) { | ||
profileImage = null; | ||
} | ||
String email = jsonNode.get("kakao_account").get("email").asText(); | ||
String kakaoId = jsonNode.get("id").asText(); | ||
|
||
return new SocialInfoDto(kakaoId, nickname, email, profileImage); | ||
} catch (JsonProcessingException e) { | ||
throw new BaseException(HttpStatus.INTERNAL_SERVER_ERROR, "카카오 계정 데이터 가공 실패"); | ||
} | ||
|
||
} | ||
|
||
} |
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
Oops, something went wrong.