Programing

안드로이드 inapp 영수증 서버검증 C++

Medeev 2016. 12. 21. 22:28
아래 설명은 OOB 리디렉션기반의 내용입니다.

구글에서 더이상 OOB 리디렉션으로 요청을 하게 되면 에러코드를 반환한다고 합니다. 

 
중요: 대역 외 (OOB) 리디렉션 메서드라고도 하는 수동 복사/붙여넣기 옵션 으로 22년 20월에 삭제될 예정입니다. 

 

/////////////////////////////////////////// 더이상 구글에서 지원하지 않습니다.!! ////////////////////////////////////
 
영수증 검증이 없을때 일어나는 상황은 유저가 구매를 하면 클라이언트는 간단하게 developer payload 등을 사용하여 간단하게 검증하고 그것이 확인되면 클라이언트에서 아이템을 지급하고 소모성아이템의 경우에는 다시 결제가 이뤄질수 있도록 Consume처리를 해주는것으로 진행됩니다.
 
하자만 결제를 진행할때 그것을 결재크랙앱등이 중간에 가로채서 app에게 결제가 된것처럼 보내는 방식 develperpayload까지 그대로 전달하기 때문에 클라이언트입장에서는 결재된것으로 판단하면 실제로 아이템을 무한정 가질 수 있게 되는것 입니다.
 
이것을 근본적으로 막을려면 클라이언트(app)가 바로 지급하고 consume 처리를 하는것을 보류하고 서버에서 아이템을 지급하되 서버가 유저가 구매한 내역을 보내오면 그것을 가지고 google이나 애플에 질의(http)하여 (영수증검증) 확인되 되는 상황에서만 아이템을 지급하는 것입니다.
 
핵심을 그러하고... 아래는 그 구현사항입니다.
 
android의 경우에는 
 
이곳에서 인앱검증을 위한 프로젝트를 생성해야 한다. 기존에 혹시 googleplaygameservice를 사용한다면 이곳에 그에 해당하는 프로젝트가 있을것이고 그렇지 않으면 하나 생성한다.

생성후 위처럼 라이브러리에 Google Play Android Developer API를 활성화 시킨다.

구글 플레이게임서비스를 사용할 경우에도 이API는 사용이 안되어있으니 활성화 시킨다.

 

이후

 

 

위처럼 사용자 인증정보를 하나 만들어야 한다. 플레이게임서비스를 사용중이면 기존에 하나가 있을것이지만 또 사용자인증정보를 만든다.

 

이 사용자가 곧 영수증 검증처리를 하는 서버가 되는것이다.

 

 

위처럼 기타로 하고 생성을 하게되면

 

 

위처럼 팝업이 뜨면서 클라이언트ID와 클라이언트 보안 비밀번호를 알려줍니다. 이것은 언제든 다시 확인할 수 있으니 따로 적어둬도 되고 나중에 확인해도 되지만, 다음 단계에서 사용될 예정입니다. 

 

여기서 클라이언트ID는 .apps.google~~ 앞부분입니다.

 

 

 

이 다음 단계가 중요한데.. OAuth라는것을 이해 해야 합니다. OAuth와 관련된 내용은 따로 검색해서 살펴보시고

아래의 참고 주소의 옵션3 : 수동복사 /  붙여넣기 방식입니다. 권장방식은 웹서버일 경우인데 현재 서버는 C++서버라서 비추천방식을 사용합니다.( 언제 지원을 중단할지 모른다고 적혀있지만..그때가서 생각해 보는것으로..)

 

참고 : https://developers.google.com/identity/protocols/OAuth2InstalledApp

 

https://accounts.google.com/o/oauth2/auth?scope=https://www.googleapis.com/auth/androidpublisher&

 

response_type=code&access_type=offline&redirect_uri=urn:ietf:wg:oauth:2.0:oob&client_id=클라이언트id
위 페이지에서 Oauth2토큰을 얻을 경우 사용해도 영수증확인시 login required 라는 에러가 뜨게됨
 
https://accounts.google.com/o/oauth2/v2/auth?scope=https://www.googleapis.com/auth/androidpublisher&

 

response_type=code&access_type=offline&redirect_uri=urn:ietf:wg:oauth:2.0:oob&client_id=클라이언트id
위 주소의 클라이언트id부분만 위에서 나온 클라이언트id로 교체하고 웹페이지에서 접속을 하면 OAuth용 token을 얻습니다.
 
이 토큰으로 실제 서버에서

 

 

string auth2 = 방금위에서얻는Oauth2토큰

 

string clientid = 클라이언트id

string clientscret = 클라이언트보안비밀

string redirecturi = "urn:ietf:wg:oauth:2.0:oob";

 

string strPostData = format( "code=%s&client_id=%s&client_secret=%s&redirect_uri=%s&grant_type=authorization_code"

, auth2.c_str(), clientid.c_str(), clientscret.c_str(), redirecturi.c_str() );

 

curl을 사용하여 

https://accounts.google.com/o/oauth2/token

여기에 위 postData를 담아 포스트로 날리면 refreshtoken이란것과 acesstoken이란것을 json형태로 알려줍니다.

 

여기까지기 준비단계고(refreshtoken과 accesstoken을 얻기위한)

 

그러면 다 왔는데.. 

실제로 영수증 검증을 요청할때는 accesstoken이 필요합니다.  영수증 요청시 패키지명, skuid, 클라이언트(app)이 알려준 결제token을 넣어서 날립니다.

 

string str = format("https://www.googleapis.com/androidpublisher/v1.1/applications/%s/inapp/%s/purchases/%s?access_token=%s" , package.c_str(), productid.c_str(), token.c_str(), accessToken.c_str() );

2019-12-01 부터 구글 정책이 v3로만 요청올 경우 유효하게 변경됨

 

string str = format("https://www.googleapis.com/androidpublisher/v3/applications/%s/purchases/products/%s/tokens/%s?access_token=%s" , package.c_str(), productid.c_str(), token.c_str(), accessToken.c_str() );

 

curl을 사용하여 Get으로 날리면 json형태의 결과값을 알려줍니다. 이 내용은 구글개발자패이지에 자세히 나오니 패스하고 정성적일때만 아이템을 지급하고 클라이언트에 알리면 클라이언트는 consume처리를 해주면됩니다.

 

그런데 문제는 이 accesstoken이 시간이 지나면 무효화되니 오래 쓸수 없습니다. json에 무효화 되는 타임이 있으니 그 전에 refreshtoken으로 다시 accesstoken을 무효화 되기전에 주기적으로 갱신시켜 줘야 합니다.

아래를 포스트로 날려 주기적으로 accesstoken을 얻어 갱신시켜 줍니다.

 

 

https://accounts.google.com/o/oauth2/token 주소로 아래 포스트로 날리면 새로 갱신된 accesstoken을 얻을수 있습니다.

 

string strPostData = format( "client_id=%s&client_secret=%s&refresh_token=%s&grant_type=refresh_token", clientid.c_str(), clientscret.c_str(), refreshtoken.c_str() );