diff --git a/.github/workflows/cd_prod.yml b/.github/workflows/cd_prod.yml index a71df5c9..a64a8b5f 100644 --- a/.github/workflows/cd_prod.yml +++ b/.github/workflows/cd_prod.yml @@ -104,7 +104,7 @@ jobs: echo "${{ secrets.DOCKERHUB_PASSWORD_PROD }}" | sudo docker login -u ${{ secrets.DOCKERHUB_USERNAME_PROD }} --password-stdin sudo docker pull ${{ secrets.DOCKERHUB_USERNAME_PROD }}/github-actions-demo sudo docker stop $(sudo docker ps -q) 2>/dev/null || true - sudo docker run --name github-actions-demo --rm -v logs:/logs -d -p 8080:8080 ${{ secrets.DOCKERHUB_USERNAME }}/github-actions-demo - sudo chmode logs 777 + sudo docker run --name github-actions-demo --rm -v logs:/logs -d -p 8080:8080 ${{ secrets.DOCKERHUB_USERNAME_PROD }}/github-actions-demo + sudo chmod logs 777 sudo docker system prune -f EOF diff --git a/src/main/java/com/twentythree/peech/common/interceptor/RequestLogInterceptor.java b/src/main/java/com/twentythree/peech/common/interceptor/RequestLogInterceptor.java index 99103c1d..2a197b95 100644 --- a/src/main/java/com/twentythree/peech/common/interceptor/RequestLogInterceptor.java +++ b/src/main/java/com/twentythree/peech/common/interceptor/RequestLogInterceptor.java @@ -27,10 +27,11 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons userId = null; funnel = "not found funnel"; } + String httpMethod = request.getMethod(); String requestURI = request.getRequestURI(); String uuid = UUID.randomUUID().toString(); - logger.info("REQUEST LOG: [ Funnel: {}, User ID: {}, Request URI: {}, UUID: {} ]", funnel, userId, requestURI, uuid); + logger.info("REQUEST LOG: [ Funnel: {}, User ID: {}, Http Method: {}, Request URI: {}, UUID: {} ]", funnel, userId, httpMethod, requestURI, uuid); return true; } diff --git a/src/main/java/com/twentythree/peech/config/WebConfig.java b/src/main/java/com/twentythree/peech/config/WebConfig.java index 5934b50c..635857ed 100644 --- a/src/main/java/com/twentythree/peech/config/WebConfig.java +++ b/src/main/java/com/twentythree/peech/config/WebConfig.java @@ -14,9 +14,8 @@ public class WebConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") - // Todo : main 으로 pr할때 origin 설정하기 .allowedOriginPatterns(allowedOrigins) - .allowedMethods("GET", "POST", "PATCH", "PUT") // 허용할 HTTP method + .allowedMethods("GET", "POST", "PATCH", "PUT", "OPTIONS") // 허용할 HTTP method .allowCredentials(true); // 쿠키 인증 요청 허용 } } diff --git a/src/main/java/com/twentythree/peech/user/dto/IdentityToken.java b/src/main/java/com/twentythree/peech/user/dto/IdentityToken.java index 6333e35c..d842cf61 100644 --- a/src/main/java/com/twentythree/peech/user/dto/IdentityToken.java +++ b/src/main/java/com/twentythree/peech/user/dto/IdentityToken.java @@ -1,11 +1,14 @@ package com.twentythree.peech.user.dto; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jws; +import io.jsonwebtoken.Jwts; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.ToString; -import java.util.List; +import java.security.PublicKey; import java.util.Objects; @Getter @@ -17,16 +20,18 @@ public class IdentityToken { private IdentityTokenHeader identityTokenHeader; private IdentityTokenPayload identityTokenPayload; - public boolean isVerify(List publicKeys) { - String alg = identityTokenHeader.getAlg(); - String kid = identityTokenHeader.getKid(); + public boolean isVerify(String jwt, PublicKey publicKey) { - for (ApplePublicKey publicKey : publicKeys) { - if (publicKey.getKid().equals(alg) && publicKey.getAlg().equals(kid)) { - return true; - } + try { + Jws jwsClaims = Jwts.parser() + .setSigningKey(publicKey) // 공개 키 설정 + .build() + .parseClaimsJws(jwt); + } catch (Exception e) { + throw new RuntimeException("토큰이 올바르지 못합니다."); } - return false; + + return true; } @Override diff --git a/src/main/java/com/twentythree/peech/user/dto/IdentityTokenPayload.java b/src/main/java/com/twentythree/peech/user/dto/IdentityTokenPayload.java index 42bfdaf4..795815a5 100644 --- a/src/main/java/com/twentythree/peech/user/dto/IdentityTokenPayload.java +++ b/src/main/java/com/twentythree/peech/user/dto/IdentityTokenPayload.java @@ -1,5 +1,6 @@ package com.twentythree.peech.user.dto; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; @@ -11,6 +12,7 @@ @AllArgsConstructor @NoArgsConstructor @ToString +@JsonIgnoreProperties(ignoreUnknown = true) public class IdentityTokenPayload { private String iss; private Long iat; diff --git a/src/main/java/com/twentythree/peech/user/dto/response/ApplePublicKeyResponseDTO.java b/src/main/java/com/twentythree/peech/user/dto/response/ApplePublicKeyResponseDTO.java index d275d4e2..3f2c3c55 100644 --- a/src/main/java/com/twentythree/peech/user/dto/response/ApplePublicKeyResponseDTO.java +++ b/src/main/java/com/twentythree/peech/user/dto/response/ApplePublicKeyResponseDTO.java @@ -1,13 +1,52 @@ package com.twentythree.peech.user.dto.response; +import com.fasterxml.jackson.annotation.JsonProperty; import com.twentythree.peech.user.dto.ApplePublicKey; +import com.twentythree.peech.user.dto.IdentityTokenHeader; +import io.jsonwebtoken.io.Decoders; import lombok.AllArgsConstructor; import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import java.math.BigInteger; +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.List; +@Slf4j @Getter @AllArgsConstructor +@NoArgsConstructor public class ApplePublicKeyResponseDTO { + + @JsonProperty("keys") private List applePublicKeys; + + public PublicKey getApplePublicKeyKey(IdentityTokenHeader identityTokenHeader) { + String alg = identityTokenHeader.getAlg(); + String kid = identityTokenHeader.getKid(); + + for (ApplePublicKey publicKey : applePublicKeys) { + if (publicKey.getKid().equals(kid) && publicKey.getAlg().equals(alg)) { + + byte[] n = Decoders.BASE64URL.decode(publicKey.getN()); + byte[] e = Decoders.BASE64URL.decode(publicKey.getE()); + RSAPublicKeySpec publicKeySpec = + new RSAPublicKeySpec(new BigInteger(1, n), new BigInteger(1, e)); + + try { + KeyFactory keyFactory = KeyFactory.getInstance(publicKey.getKty()); + return keyFactory.generatePublic(publicKeySpec); + } catch (NoSuchAlgorithmException | InvalidKeySpecException exception) { + throw new RuntimeException("응답 받은 Apple Public Key로 PublicKey를 생성할 수 없습니다."); + } + } + } + + throw new RuntimeException("Token을 검증할 수 없습니다."); + } } diff --git a/src/main/java/com/twentythree/peech/user/service/UserServiceImpl.java b/src/main/java/com/twentythree/peech/user/service/UserServiceImpl.java index 49dc025e..85252404 100644 --- a/src/main/java/com/twentythree/peech/user/service/UserServiceImpl.java +++ b/src/main/java/com/twentythree/peech/user/service/UserServiceImpl.java @@ -99,7 +99,7 @@ public LoginBySocial loginBySocial(String socialToken, AuthorizationServer autho ApplePublicKeyResponseDTO publicKeys = appleLoginClient.getPublicKeys(); - if (identityToken.isVerify(publicKeys.getApplePublicKeys())) { + if (identityToken.isVerify(socialToken, publicKeys.getApplePublicKeyKey(identityToken.getIdentityTokenHeader()))) { userEmail = identityToken.getIdentityTokenPayload().getEmail(); } else { throw new Unauthorized("애플로그인에서 토큰이 유효하지 않습니다.");