-
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.
Merge pull request #12 from Team-Going/feature/9
[feat] 소셜 로그인 OpenFeign 관련 세팅
- Loading branch information
Showing
14 changed files
with
263 additions
and
0 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
10 changes: 10 additions & 0 deletions
10
doorip-external/src/main/java/org/doorip/config/FeignClientConfig.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.doorip.config; | ||
|
||
import org.doorip.ExternalRoot; | ||
import org.springframework.cloud.openfeign.EnableFeignClients; | ||
import org.springframework.context.annotation.Configuration; | ||
|
||
@Configuration | ||
@EnableFeignClients(basePackageClasses = ExternalRoot.class) | ||
public class FeignClientConfig { | ||
} |
10 changes: 10 additions & 0 deletions
10
doorip-external/src/main/java/org/doorip/openfeign/apple/AppleFeignClient.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.doorip.openfeign.apple; | ||
|
||
import org.springframework.cloud.openfeign.FeignClient; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
|
||
@FeignClient(name = "${oauth.apple.name}", url = "${oauth.apple.url}") | ||
public interface AppleFeignClient { | ||
@GetMapping("/keys") | ||
ApplePublicKeys getApplePublicKeys(); | ||
} |
47 changes: 47 additions & 0 deletions
47
doorip-external/src/main/java/org/doorip/openfeign/apple/AppleIdentityTokenParser.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,47 @@ | ||
package org.doorip.openfeign.apple; | ||
|
||
import com.fasterxml.jackson.core.JsonProcessingException; | ||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
import io.jsonwebtoken.*; | ||
import org.doorip.exception.UnauthorizedException; | ||
import org.doorip.message.ErrorMessage; | ||
import org.springframework.stereotype.Component; | ||
|
||
import java.nio.charset.StandardCharsets; | ||
import java.security.Key; | ||
import java.security.PublicKey; | ||
import java.util.Base64; | ||
import java.util.Map; | ||
|
||
@Component | ||
public class AppleIdentityTokenParser { | ||
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); | ||
|
||
public Map<String, String> parseHeaders(String identityToken) { | ||
try { | ||
String encoded = identityToken.split("\\.")[0]; | ||
String decoded = new String(Base64.getUrlDecoder().decode(encoded), StandardCharsets.UTF_8); | ||
return OBJECT_MAPPER.readValue(decoded, Map.class); | ||
} catch (JsonProcessingException | ArrayIndexOutOfBoundsException e) { | ||
throw new UnauthorizedException(ErrorMessage.INVALID_IDENTITY_TOKEN); | ||
} | ||
} | ||
|
||
public Claims parseWithPublicKeyAndGetClaims(String identityToken, PublicKey publicKey) { | ||
try { | ||
return getJwtParser(publicKey) | ||
.parseClaimsJws(identityToken) | ||
.getBody(); | ||
} catch (ExpiredJwtException e) { | ||
throw new UnauthorizedException(ErrorMessage.EXPIRED_IDENTITY_TOKEN); | ||
} catch (UnsupportedJwtException | MalformedJwtException | IllegalArgumentException e) { | ||
throw new UnauthorizedException(ErrorMessage.INVALID_IDENTITY_TOKEN_VALUE); | ||
} | ||
} | ||
|
||
private JwtParser getJwtParser(Key key) { | ||
return Jwts.parserBuilder() | ||
.setSigningKey(key) | ||
.build(); | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
doorip-external/src/main/java/org/doorip/openfeign/apple/AppleIdentityTokenValidator.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,18 @@ | ||
package org.doorip.openfeign.apple; | ||
|
||
import io.jsonwebtoken.Claims; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.stereotype.Component; | ||
|
||
@Component | ||
public class AppleIdentityTokenValidator { | ||
@Value("${oauth.apple.iss}") | ||
private String iss; | ||
@Value("${oauth.apple.client-id}") | ||
private String clientId; | ||
|
||
public boolean isValidAppleIdentityToken(Claims claims) { | ||
return claims.getIssuer().contains(iss) | ||
&& claims.getAudience().equals(clientId); | ||
} | ||
} |
35 changes: 35 additions & 0 deletions
35
doorip-external/src/main/java/org/doorip/openfeign/apple/AppleOAuthProvider.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,35 @@ | ||
package org.doorip.openfeign.apple; | ||
|
||
import io.jsonwebtoken.Claims; | ||
import lombok.RequiredArgsConstructor; | ||
import org.doorip.exception.UnauthorizedException; | ||
import org.doorip.message.ErrorMessage; | ||
import org.springframework.stereotype.Component; | ||
|
||
import java.security.PublicKey; | ||
import java.util.Map; | ||
|
||
@RequiredArgsConstructor | ||
@Component | ||
public class AppleOAuthProvider { | ||
private final AppleFeignClient appleFeignClient; | ||
private final AppleIdentityTokenParser appleIdentityTokenParser; | ||
private final ApplePublicKeyGenerator applePublicKeyGenerator; | ||
private final AppleIdentityTokenValidator appleIdentityTokenValidator; | ||
|
||
public String getApplePlatformId(String identityToken) { | ||
Map<String, String> headers = appleIdentityTokenParser.parseHeaders(identityToken); | ||
ApplePublicKeys applePublicKeys = appleFeignClient.getApplePublicKeys(); | ||
PublicKey publicKey = applePublicKeyGenerator.generatePublicKeyWithApplePublicKeys(headers, applePublicKeys); | ||
Claims claims = appleIdentityTokenParser.parseWithPublicKeyAndGetClaims(identityToken, publicKey); | ||
validateClaims(claims); | ||
|
||
return claims.getSubject(); | ||
} | ||
|
||
private void validateClaims(Claims claims) { | ||
if (!appleIdentityTokenValidator.isValidAppleIdentityToken(claims)) { | ||
throw new UnauthorizedException(ErrorMessage.INVALID_IDENTITY_TOKEN_CLAIMS); | ||
} | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
doorip-external/src/main/java/org/doorip/openfeign/apple/ApplePublicKey.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.doorip.openfeign.apple; | ||
|
||
public record ApplePublicKey( | ||
String kty, | ||
String kid, | ||
String use, | ||
String alg, | ||
String n, | ||
String e) { | ||
} | ||
|
35 changes: 35 additions & 0 deletions
35
doorip-external/src/main/java/org/doorip/openfeign/apple/ApplePublicKeyGenerator.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,35 @@ | ||
package org.doorip.openfeign.apple; | ||
|
||
import org.doorip.exception.UnauthorizedException; | ||
import org.doorip.message.ErrorMessage; | ||
import org.springframework.stereotype.Component; | ||
|
||
import java.security.KeyFactory; | ||
import java.security.NoSuchAlgorithmException; | ||
import java.security.PublicKey; | ||
import java.security.spec.InvalidKeySpecException; | ||
import java.security.spec.RSAPublicKeySpec; | ||
import java.util.Base64; | ||
import java.util.Map; | ||
import java.math.BigInteger; | ||
|
||
@Component | ||
public class ApplePublicKeyGenerator { | ||
public PublicKey generatePublicKeyWithApplePublicKeys(Map<String, String> headers, ApplePublicKeys applePublicKeys) { | ||
ApplePublicKey applePublicKey = applePublicKeys | ||
.getMatchesKey(headers.get("alg"), headers.get("kid")); | ||
|
||
byte[] nBytes = Base64.getUrlDecoder().decode(applePublicKey.n()); | ||
byte[] eBytes = Base64.getUrlDecoder().decode(applePublicKey.e()); | ||
|
||
RSAPublicKeySpec rsaPublicKeySpec = new RSAPublicKeySpec( | ||
new BigInteger(1, nBytes), new BigInteger(1, eBytes)); | ||
|
||
try { | ||
KeyFactory keyFactory = KeyFactory.getInstance(applePublicKey.kty()); | ||
return keyFactory.generatePublic(rsaPublicKeySpec); | ||
} catch (NoSuchAlgorithmException | InvalidKeySpecException exception) { | ||
throw new UnauthorizedException(ErrorMessage.UNABLE_TO_CREATE_APPLE_PUBLIC_KEY); | ||
} | ||
} | ||
} |
17 changes: 17 additions & 0 deletions
17
doorip-external/src/main/java/org/doorip/openfeign/apple/ApplePublicKeys.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 org.doorip.openfeign.apple; | ||
|
||
import org.doorip.exception.UnauthorizedException; | ||
import org.doorip.message.ErrorMessage; | ||
|
||
import java.util.List; | ||
|
||
public class ApplePublicKeys { | ||
private List<ApplePublicKey> keys; | ||
|
||
public ApplePublicKey getMatchesKey(String alg, String kid) { | ||
return keys.stream() | ||
.filter(applePublicKey -> applePublicKey.alg().equals(alg) && applePublicKey.kid().equals(kid)) | ||
.findFirst() | ||
.orElseThrow(() -> new UnauthorizedException(ErrorMessage.INVALID_IDENTITY_TOKEN)); | ||
} | ||
} |
20 changes: 20 additions & 0 deletions
20
doorip-external/src/main/java/org/doorip/openfeign/kakao/KakaoAccessToken.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.doorip.openfeign.kakao; | ||
|
||
import lombok.AccessLevel; | ||
import lombok.AllArgsConstructor; | ||
import lombok.Getter; | ||
|
||
@AllArgsConstructor(access = AccessLevel.PRIVATE) | ||
@Getter | ||
public class KakaoAccessToken { | ||
private static final String TOKEN_TYPE = "Bearer "; | ||
private String accessToken; | ||
|
||
public static KakaoAccessToken createKakaoAccessToken(String accessToken) { | ||
return new KakaoAccessToken(accessToken); | ||
} | ||
|
||
public String getAccessTokenWithTokenType() { | ||
return TOKEN_TYPE + accessToken; | ||
} | ||
} |
6 changes: 6 additions & 0 deletions
6
doorip-external/src/main/java/org/doorip/openfeign/kakao/KakaoAccessTokenInfo.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,6 @@ | ||
package org.doorip.openfeign.kakao; | ||
|
||
public record KakaoAccessTokenInfo( | ||
Long id | ||
) { | ||
} |
12 changes: 12 additions & 0 deletions
12
doorip-external/src/main/java/org/doorip/openfeign/kakao/KakaoFeignClient.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.doorip.openfeign.kakao; | ||
|
||
import org.springframework.cloud.openfeign.FeignClient; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.RequestHeader; | ||
|
||
@FeignClient(name = "${oauth.kakao.name}", url = "${oauth.kakao.url}") | ||
public interface KakaoFeignClient { | ||
@GetMapping | ||
KakaoAccessTokenInfo getKakaoAccessTokenInfo(@RequestHeader("Authorization") String accessTokenWithTokenType); | ||
} | ||
|
31 changes: 31 additions & 0 deletions
31
doorip-external/src/main/java/org/doorip/openfeign/kakao/KakaoOAuthProvider.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,31 @@ | ||
package org.doorip.openfeign.kakao; | ||
|
||
import feign.FeignException; | ||
import lombok.RequiredArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.doorip.exception.UnauthorizedException; | ||
import org.doorip.message.ErrorMessage; | ||
import org.springframework.stereotype.Component; | ||
|
||
@Slf4j | ||
@RequiredArgsConstructor | ||
@Component | ||
public class KakaoOAuthProvider { | ||
private final KakaoFeignClient kakaoFeignClient; | ||
|
||
public String getKakaoPlatformId(String accessToken) { | ||
KakaoAccessToken kakaoAccessToken = KakaoAccessToken.createKakaoAccessToken(accessToken); | ||
String accessTokenWithTokenType = kakaoAccessToken.getAccessTokenWithTokenType(); | ||
KakaoAccessTokenInfo kakaoAccessTokenInfo = getKakaoAccessTokenInfo(accessTokenWithTokenType); | ||
return String.valueOf(kakaoAccessTokenInfo.id()); | ||
} | ||
|
||
private KakaoAccessTokenInfo getKakaoAccessTokenInfo(String accessTokenWithTokenType) { | ||
try { | ||
return kakaoFeignClient.getKakaoAccessTokenInfo(accessTokenWithTokenType); | ||
} catch (FeignException e) { | ||
log.error("Feign Exception: ", e); | ||
throw new UnauthorizedException(ErrorMessage.INVALID_KAKAO_ACCESS_TOKEN); | ||
} | ||
} | ||
} |