Skip to content

Commit

Permalink
Merge pull request #31 from Team-UMC/feature/#17/social-login
Browse files Browse the repository at this point in the history
[FEAT] 소셜 로그인 기능 구현
  • Loading branch information
junseokkim authored Jan 22, 2024
2 parents 6317f68 + 4d2d207 commit 479b1bb
Show file tree
Hide file tree
Showing 23 changed files with 497 additions and 50 deletions.
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ dependencies {
// swagger setting
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0'

// webClient setting
implementation 'org.springframework.boot:spring-boot-starter-webflux'

// s3 setting
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package com.umc.networkingService.config.security.jwt;

import com.umc.networkingService.config.security.auth.PrincipalDetails;
import com.umc.networkingService.domain.member.dto.MemberResponseDto;
import io.jsonwebtoken.*;
import com.umc.networkingService.config.security.auth.PrincipalDetailsService;
import com.umc.networkingService.global.common.exception.ErrorCode;
import com.umc.networkingService.global.common.exception.RestApiException;
Expand Down Expand Up @@ -40,7 +38,7 @@ public class JwtTokenProvider {

private static final String AUTHORIZATION_HEADER = "Authorization";
private static final String REFRESH_HEADER = "refreshToken";
private static final long TOKEN_VALID_TIME = 1000 * 60L * 60L; // 유효기간 1시간
private static final long TOKEN_VALID_TIME = 1000 * 60L * 60L * 24L; // 유효기간 1일
private static final long REF_TOKEN_VALID_TIME = 1000 * 60L * 60L * 24L * 14L; // 유효기간 14일

@PostConstruct
Expand All @@ -49,7 +47,7 @@ protected void init() {
refreshSecretKey = Base64.getEncoder().encodeToString(refreshSecretKey.getBytes());
}

public String generateAccessToken(Claims claims, UUID memberId) {
public String generateAccessToken(Claims claims) {
Date now = new Date();
Date accessTokenExpirationTime = new Date(now.getTime() + TOKEN_VALID_TIME);

Expand All @@ -61,7 +59,7 @@ public String generateAccessToken(Claims claims, UUID memberId) {
.compact();
}

public String generateRefreshToken(Claims claims, UUID memberId) {
public String generateRefreshToken(Claims claims) {
Date now = new Date();
Date refreshTokenExpirationTime = new Date(now.getTime() + REF_TOKEN_VALID_TIME);

Expand All @@ -73,15 +71,15 @@ public String generateRefreshToken(Claims claims, UUID memberId) {
.compact();
}

public MemberResponseDto.TokenInfo generateToken(UUID memberId) {
public TokenInfo generateToken(UUID memberId) {

Claims claims = Jwts.claims();
claims.put("memberId", memberId);

String accessToken = generateAccessToken(claims, memberId);
String refreshToken = generateRefreshToken(claims, memberId);
String accessToken = generateAccessToken(claims);
String refreshToken = generateRefreshToken(claims);

return new MemberResponseDto.TokenInfo(accessToken, refreshToken);
return new TokenInfo(accessToken, refreshToken);
}

public Authentication getAuthentication(String token) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.umc.networkingService.config.security.jwt;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;


@Getter
@Builder
@AllArgsConstructor
public class TokenInfo {

private String accessToken;
private String refreshToken;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.umc.networkingService.domain.member.client;

import com.umc.networkingService.domain.member.dto.client.AppleResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;

@Component
public class AppleMemberClient {
private WebClient webClient;

public AppleMemberClient(WebClient.Builder webclientBuilder){
this.webClient = webclientBuilder
.baseUrl("https://appleid.apple.com/auth/keys")
.build();
}

public String getappleClientID(final String accessToken){
AppleResponse response = webClient.get()
.header("Authorization", "Bearer " + accessToken)
.retrieve()
.bodyToMono(AppleResponse.class)
.block();

//TODO 정보 받기 실패 예외 처리
if(response == null)
return null;

return response.getSub();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.umc.networkingService.domain.member.client;

import com.umc.networkingService.domain.member.dto.client.GoogleResponse;
import com.umc.networkingService.global.common.exception.ErrorCode;
import com.umc.networkingService.global.common.exception.RestApiException;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;

@Component
public class GoogleMemberClient {
private final WebClient webClient;

public GoogleMemberClient(WebClient.Builder webClientBuilder){
this.webClient = webClientBuilder
.baseUrl("https://www.googleapis.com/oauth2/v3/userinfo")
.build();
}

public String getgoogleClientID(final String accessToken) {
GoogleResponse response = webClient.get()
.header("Authorization", "Bearer " + accessToken)
.retrieve()
.bodyToMono(GoogleResponse.class)
.block();

if(response == null)
throw new RestApiException(ErrorCode._INTERNAL_SERVER_ERROR);

return response.getSub();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.umc.networkingService.domain.member.client;

import com.umc.networkingService.domain.member.dto.client.KakaoResponse;
import com.umc.networkingService.global.common.exception.ErrorCode;
import com.umc.networkingService.global.common.exception.RestApiException;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;

@Component
public class KakaoMemberClient {

private final WebClient webClient;


public KakaoMemberClient(WebClient.Builder webClientBuilder ) {
this.webClient = webClientBuilder
.baseUrl("https://kapi.kakao.com/v2/user/me")
.build();
}

public String getkakaoClientID(final String accessToken) {
KakaoResponse response = webClient.get()
.header("Authorization", "Bearer " + accessToken)
.retrieve()
.bodyToMono(KakaoResponse.class)
.block();

if(response == null)
throw new RestApiException(ErrorCode._INTERNAL_SERVER_ERROR);

return response.getId();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.umc.networkingService.domain.member.client;

import com.umc.networkingService.domain.member.dto.client.NaverResponse;
import com.umc.networkingService.global.common.exception.ErrorCode;
import com.umc.networkingService.global.common.exception.RestApiException;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;

@Component
public class NaverMemberClient {

private final WebClient webClient;

public NaverMemberClient(WebClient.Builder webClientBuilder){
this.webClient=webClientBuilder
.baseUrl("https://openapi.naver.com/v1/nid/me")
.build();
}

public String getnaverClientID(final String accessToken){
NaverResponse response=webClient.get()
.header("Authorization","Bearer "+ accessToken)
.retrieve()
.bodyToMono(NaverResponse.class)
.block();

if(response == null)
throw new RestApiException(ErrorCode._INTERNAL_SERVER_ERROR);

return response.getResponse().getId();
}
}
Original file line number Diff line number Diff line change
@@ -1,25 +1,23 @@
package com.umc.networkingService.domain.member.controller;


import com.umc.networkingService.config.security.auth.CurrentMember;
import com.umc.networkingService.config.security.jwt.JwtTokenProvider;
import com.umc.networkingService.domain.member.dto.request.MemberSignUpRequest;
import com.umc.networkingService.domain.member.dto.response.MemberLoginResponse;
import com.umc.networkingService.domain.member.dto.response.MemberSignUpResponse;
import com.umc.networkingService.domain.member.entity.Member;
import com.umc.networkingService.domain.member.entity.SocialType;
import com.umc.networkingService.domain.member.repository.MemberRepository;
import com.umc.networkingService.domain.member.service.MemberService;
import com.umc.networkingService.global.common.base.BaseResponse;
import com.umc.networkingService.global.common.enums.Role;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
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;
import org.springframework.web.bind.annotation.*;

@Tag(name = "멤버 API", description = "멤버 관련 API")
@RestController
Expand All @@ -28,6 +26,20 @@
public class MemberController {

private final MemberService memberService;

@Operation(summary = "소셜 로그인", description = "네이버, 카카오, 구글, 애플 로그인")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "로그인 성공"),
@ApiResponse(responseCode = "COMMON500", description = "소셜 서버와의 통신 에러" , content =
@Content(schema = @Schema(implementation = BaseResponse.class)))
})
@PostMapping("/login")
public BaseResponse<MemberLoginResponse> socialLogin(@RequestParam(value = "accessToken") String accessToken,
@RequestParam(value = "socialType") SocialType socialType) {
return BaseResponse.onSuccess(memberService.socialLogin(accessToken, socialType));

}

@Operation(summary = "회원가입 API", description = "최초 멤버 정보를 등록하는 API입니다.")
@ApiResponses( value = {
@ApiResponse(responseCode = "COMMON200", description = "성공"),
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.umc.networkingService.domain.member.dto.client;

import lombok.Getter;

@Getter
public class AppleResponse {
private String sub;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.umc.networkingService.domain.member.dto.client;

import lombok.Getter;

@Getter
public class GoogleResponse {
private String sub;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.umc.networkingService.domain.member.dto.client;

import lombok.Getter;

@Getter
public class KakaoResponse {
private String id;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.umc.networkingService.domain.member.dto.client;

import lombok.Getter;

@Getter
public class NaverResponse {
private Response response;

@Getter
public static class Response {
private String id;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.umc.networkingService.domain.member.dto.response;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;

import java.util.UUID;

@Getter
@Builder
public class MemberLoginResponse {
private UUID memberId;
private String accessToken;
private String refreshToken;
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
@Getter
@Entity
@Builder
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@SQLRestriction("deleted_at is null")
@DynamicInsert
public class Member extends BaseEntity {
Expand All @@ -31,6 +31,7 @@ public class Member extends BaseEntity {
@Column(name = "member_id")
private UUID id;

@Column(nullable = false)
private String clientId;

@ManyToOne(fetch = FetchType.LAZY)
Expand All @@ -52,6 +53,7 @@ public class Member extends BaseEntity {

private String statusMessage;

@Enumerated(EnumType.STRING)
@Column(nullable = false)
private SocialType socialType;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
@AllArgsConstructor
@Getter
@Builder
@RedisHash(value = "jwtToken", timeToLive = 60*60*24*30) // 30일
@RedisHash(value = "jwtToken", timeToLive = 60*60*24*14) // 14일
public class RefreshToken { //redis에 저장할 객체

@Id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
public enum SocialType {
KAKAO("카카오"),
GOOGLE("구글"),
NAVER("네이버"),
APPLE("애플");

private final String toKorean;
Expand Down
Loading

0 comments on commit 479b1bb

Please sign in to comment.