-
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.
Feat: #196 구글 인앱 결제(영수증 검증) API 추가 + CI/CD 파일에 google-acoount-key 생성 …
…부분 추가
- Loading branch information
Showing
6 changed files
with
127 additions
and
1 deletion.
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
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
26 changes: 26 additions & 0 deletions
26
genti-api/src/main/java/com/gt/genti/purchase/controller/UserPurchaseController.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,26 @@ | ||
package com.gt.genti.purchase.controller; | ||
|
||
import com.gt.genti.purchase.dto.request.PurchaseRequestDto; | ||
import com.gt.genti.purchase.service.InAppPurchaseService; | ||
import com.gt.genti.response.GentiResponse; | ||
import com.gt.genti.user.model.AuthUser; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.PostMapping; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.RestController; | ||
|
||
@RestController | ||
@RequestMapping("/api/v1/users/in-app-purchases") | ||
@RequiredArgsConstructor | ||
public class UserPurchaseController { | ||
|
||
private final InAppPurchaseService inAppPurchaseService; | ||
|
||
@PostMapping("/google/receipt-validation") | ||
public ResponseEntity<GentiResponse.ApiResult<Boolean>> validateReceipt( | ||
@AuthUser Long userId, | ||
PurchaseRequestDto purchaseRequestDto) { | ||
return GentiResponse.success(inAppPurchaseService.validateReceipt(userId, purchaseRequestDto)); | ||
} | ||
} |
10 changes: 10 additions & 0 deletions
10
genti-api/src/main/java/com/gt/genti/purchase/dto/request/PurchaseRequestDto.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 com.gt.genti.purchase.dto.request; | ||
|
||
import lombok.Getter; | ||
|
||
@Getter | ||
public class PurchaseRequestDto { | ||
private String packageName; //인앱 상품이 판매된 애플리케이션의 패키지 이름 | ||
private String productId; //인앱 상품 SKU | ||
private String purchaseToken; //안드로이드에서 받아올 구매 토큰 | ||
} |
78 changes: 78 additions & 0 deletions
78
genti-api/src/main/java/com/gt/genti/purchase/service/InAppPurchaseService.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,78 @@ | ||
package com.gt.genti.purchase.service; | ||
|
||
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; | ||
import com.google.api.client.http.HttpTransport; | ||
import com.google.api.client.json.JsonFactory; | ||
import com.google.api.client.json.gson.GsonFactory; | ||
import com.google.api.services.androidpublisher.AndroidPublisher; | ||
import com.google.api.services.androidpublisher.AndroidPublisherScopes; | ||
import com.google.api.services.androidpublisher.model.ProductPurchase; | ||
import com.google.auth.http.HttpCredentialsAdapter; | ||
import com.google.auth.oauth2.GoogleCredentials; | ||
import com.gt.genti.purchase.dto.request.PurchaseRequestDto; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.core.io.ClassPathResource; | ||
import org.springframework.stereotype.Service; | ||
|
||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.security.GeneralSecurityException; | ||
|
||
@Service | ||
public class InAppPurchaseService { | ||
|
||
@Value("{google-account.file-path}") | ||
private String googleAccountFilePath; | ||
|
||
@Value("{google-application.package-name}") | ||
private String googleApplicationPackageName; | ||
|
||
public Boolean validateReceipt(Long userId, PurchaseRequestDto purchaseRequestDto) { | ||
|
||
try { | ||
// ================= Google Credential 생성 ================= | ||
JsonFactory JSON_FACTORY = GsonFactory.getDefaultInstance(); | ||
HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport(); | ||
|
||
InputStream inputStream = new ClassPathResource(googleAccountFilePath).getInputStream(); | ||
GoogleCredentials credentials = GoogleCredentials | ||
.fromStream(inputStream) | ||
.createScoped(AndroidPublisherScopes.ANDROIDPUBLISHER); | ||
|
||
// ======================== API 호출 ======================== | ||
AndroidPublisher.Builder builder = new AndroidPublisher.Builder(httpTransport, JSON_FACTORY, new HttpCredentialsAdapter(credentials)); | ||
AndroidPublisher publisher = builder.setApplicationName(googleApplicationPackageName).build(); | ||
AndroidPublisher.Purchases.Products.Get gas = publisher.purchases() | ||
.products() | ||
.get( | ||
"packageName", | ||
"productId", | ||
"purchaseToken"); | ||
ProductPurchase purchase = gas.execute(); | ||
|
||
AndroidPublisher.Purchases.Products.Get get = publisher.purchases().products() | ||
.get(purchaseRequestDto.getPackageName(), purchaseRequestDto.getProductId(), purchaseRequestDto.getPurchaseToken()); //inapp 아이템의 구매 및 소모 상태 확인 | ||
ProductPurchase productPurchase = get.execute(); //검증 결과 | ||
System.out.println(productPurchase.toPrettyString()); | ||
|
||
// 인앱 상품의 소비 상태. 0 아직 소비 안됨(Yet to be consumed) / 1 소비됨(Consumed) | ||
Integer consumptionState = productPurchase.getConsumptionState(); | ||
|
||
// 개발자가 지정한 임의 문자열 정보 | ||
String developerPayload = productPurchase.getDeveloperPayload(); | ||
|
||
// 구매 상태. 0 구매완료 / 1 취소됨 | ||
Integer purchaseState = productPurchase.getPurchaseState(); | ||
if(purchaseState == 1){ | ||
return false; | ||
} | ||
|
||
// 상품이 구매된 시각. 타임스탬프 형태 | ||
Long purchaseTimeMillis = productPurchase.getPurchaseTimeMillis(); | ||
|
||
return true; | ||
} catch (IOException | GeneralSecurityException e) { | ||
return false; | ||
} | ||
} | ||
} |