Skip to content

サーバー側接続インターフェース説明

もしあなたのゲームに独自のゲームサーバーがあり、ゲームプレイヤーデータをサーバー側で保存・管理している場合、サーバー側での接続が必要です:

モジュール説明接続推奨
ユーザーシステムJogosプラットフォームのユーザーシステムをあなたのサーバーのユーザーと関連付ける必要があります。サーバー側でユーザーシステムに接続する必要があります☑️必須接続
課金システムあなたのゲームに課金項目がある場合、Jogos課金システムに接続する必要があります。これにより、ユーザーの支払いとデータの安全性が保証されます☑️課金ゲームは必須接続

ユーザーシステム接続

1 クライアントからユーザートークンを取得

2 概要

Jogosからユーザートークンおよびpublickeyを取得後、ゲームサーバーに返送して検証を行い、ユーザー情報を取得します。注意:トークンを検証するたびにpublickeyを取得してください。publickeyは随時変更される可能性があります。

3 検証ロジック

  • ゲーム開発者はJogosから取得したユーザートークンを自分のサーバーに送信します。
  • サーバー側でpublickeyを取得します(https://www.jogos.com/publicKey.json から取得)。
  • Base64エンコードされたpublickey文字列からRSA公開鍵を生成。
  • RSA公開鍵を使用してJWTトークンを復号化します。復号化結果は jwt.io でテスト可能です。
  • 復号化後に取得したユーザー情報をあなたのゲームサーバーのユーザーと紐付けます。
  • 復号化が失敗した場合、空のユーザー情報を返します。

4 コード例

  プロジェクトにjwtをインポート:
  <!--JWT-->
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt-api</artifactId>
        <version>0.11.2</version>
    </dependency>
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt-impl</artifactId>
        <version>0.11.2</version>
    </dependency>
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt-jackson</artifactId>
        <version>0.11.2</version>
    </dependency>
java
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.Map;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import com.alibaba.fastjson.JSONObject;

public class JwtUtils {

	
	public static void main(String[] args) {
		/**
		 * Jogos SDKからpublickeyとユーザートークンを取得し、サーバーに送信
		 * 以下は例のpublickey:
		  
		  -----BEGIN PUBLIC KEY-----
		  MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhyUrr/W8bSuC+HK8Rk++BDOGDefGMEBa9jekVwVE3oeqi7QbVzZPAuqb1K3GPJjDBfi44IWzb3w8Xa0P1ZeO2Cnbg1LltanlzFv/EcKseCIkOd8Qo78ARPfmlf4WP6MznYGKwNVGFh/s5Y6ar8QgWX1ttkcwYzHu/gUroO+nPOZkU6bfxHjRrJxk3lSQBZWfTSFd2JFwntq3h45UHymjQZiMtW47G2C4VTtTTt1Iz0VQ9rdtWie/+REqQYoFUm04Yns9jyG3TZzio9vsRrxESLQbBIRxto77cQNtEe9j/2EXNwQabRkiS6zo6i2TIN4O6uthWBVud5WXsBWdiyIOHQIDAQAB
		  -----END PUBLIC KEY-----

		ユーザートークン:
		  eyJhbGciOiJSUzI1NiJ9.eyJqdGkiOiIxOTY3NDIzNTM3NjE1NTgxMTg0Iiwic3ViIjoie1wicHJvZmlsZVBpY3R1cmVVcmxcIjpcImh0dHBzOi8vaW1hZ2Uuam9nb3NwcmUuY29tLzBlZTkyZjViZTRhMzQ4NzBhYjY0YWU1N2FjN2I1YmE0LmpwZ1wiLFwiZ2FtZUlkXCI6XCIxMjIwXCIsXCJ1c2VySWRcIjpcIjI1N1wiLFwidXNlcm5hbWVcIjpcIlBsYXllcjI1N1wifSIsImlzcyI6ImNvbTpqb2dvczpzZGsiLCJpYXQiOjE3NTc5MDUyOTgsImV4cCI6MTc2MTUwNTI5OH0.MKBab0XC1o5AYGosbq1l5m9xCLN1-4xfcr7_dHn-_C8Eh2moTuq9TbQutIajB3dViFW0e1KyIg7UhxNk00rdhT2b5UrvO23tyFsgg9FYyAyCZABURxHyI0lTW9V8YA9k4faycK_gCUMXH_IubseDMz1P7cYmPpo8WxJXZq3R-mL8OhhuKCn8DlpP5BVsd0_gYSTvDUD0gjdINLUNTVrZVkETcDVWW8OXQVzJxdTH0VVlDs4cGvIyko8TJ6g1Bvz4VWj4qy1XoQFfRBH8sgBl3oGJtUodhq3b4bOx4Cr_o-2tK54CetDdmmCPbtcbmmDcBqK5EQ51A2Kws-1cYtsFxg
		     
		  注:トークン検証時は毎回publickeyを取得してください。変更される可能性があります。
		 */
		
		String publickey ="あなたのpublickey";
		String token = "あなたのユーザートークン";
		
		System.out.println("publickey:["+publickey+"]");
		System.out.println("token:["+token+"]");
		Map<String, Object> userMap = verifyToken(token,publickey);
		// Token解析成功の場合、userMapはnullではない
        if (userMap != null) {
        	System.out.println("検証成功、ユーザー情報:");
        	System.out.println(JSONObject.toJSONString(userMap));
        }else {
        	System.out.println("jwt検証失敗");
        }
	}
	
	
	/**
	 * トークン検証
	 * @param token
	 * @return
	 */
	public static Map<String, Object> verifyToken(String token,String publickey){  
		
		// トークン解析を試み、失敗した場合はnullを返す
		Map<String, Object> map = null;
        try {
        	map = parseToken(token,publickey);
        } catch (Exception e) {
            
        }
        return map;
         
    }
	
	/**
	 * トークン復号
	 * @param token
	 * @return
	 */
	public static Map<String,Object> parseToken(String token,String publickey){
		// 先頭と末尾を削除
		if(publickey.startsWith("-----BEGIN PUBLIC KEY-----")) {
			publickey = publickey.substring(27,publickey.length()-25);
		}
		Claims claims = (Claims) Jwts.parser()
	                .setSigningKey(getPublicKey(publickey))
	                .parse(token)
	                .getBody();
        String parseToken = claims.getSubject();
        
        if (parseToken != null) {
        	Map<String, Object> map = JSONObject.parseObject(parseToken, Map.class);
			return map;
        }
        return null;
    }
	
	 /**
     * Base64エンコード文字列からRSA公開鍵を取得
     * @param key Base64エンコードされた公開鍵文字列
     * @return 変換後のRSA公開鍵
     * <p>
     * 注意:入力文字列をBase64デコーダーでバイト配列に変換後、KeyFactoryとX509EncodedKeySpecを使用してPublicKeyオブジェクトに変換します。
     * 変換中に例外が発生した場合はRuntimeExceptionをスローします。
     */
    private static PublicKey getPublicKey(String key) {
        byte[] decode = Base64.getDecoder().decode(key);
        PublicKey publicKey;
        try {
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decode);
            publicKey = keyFactory.generatePublic(keySpec);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return publicKey;
    }
}

課金システム接続

接続開始前の確認事項

  • 現在使用している環境が www.jogospre.com(テスト環境)または www.jogos.com(本番環境)であることを確認してください。以下に記載されるPOSTリクエストURLは、対応する環境のURLに変更する必要があります。 (例:テスト環境の到着API:https://api.jogospre.com/api/gamepay/webhook/arrivedorder)

  • 開発者プラットフォームでゲームアプリを作成し、「ゲームパラメータ」でゲームの 共有キー を生成済みであること。

  • ゲーム設定で「アプリ内課金」を有効にし、サーバーが受信する コールバック通知URL を入力済みであること。

  • 通信はSHA-1暗号化方式を使用。使用例は以下の通り:

    javascript
    private String sha1(String input) {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-1");
            byte[] hashInBytes = md.digest(input.getBytes(StandardCharsets.UTF_8));
    
            StringBuilder sb = new StringBuilder();
            for (byte b : hashInBytes) {
                sb.append(String.format("%02x", b));
            }
            return sb.toString();
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("SHA-1 algorithm is not available", e);
        }
    }

クライアント側の事前接続:

  • クライアント側で注文作成および注文送信を行います。
  • 詳細は クライアント接続課金SDK ドキュメントを参照してください。

サーバー側接続開始:

1. ユーザーがゲーム内で商品購入成功後、Jogosプラットフォームが支払い成功通知を送信

  • Jogosプラットフォームは支払い成功コールバック情報を、あなたが設定した コールバック通知URL に送信

  • リクエストヘッダ:

    フィールド名タイプ空許可説明
    Authorizationstring検証ヘッダ。sha1(body+キー)、キーはゲームの共有キー(ゲームパラメータで設定)
  • リクエストボディには以下のフィールドが含まれます:

    フィールド名タイプ空許可説明
    paytypeString通知タイプ pay:支払い成功通知;refund:返金成功通知
    gameIdintゲームID
    orderIdString注文番号
    arrivedStatusint到着ステータス:0 未到着,1 到着済み
    productIdString商品ID
    createTimelong注文作成時間(Unixタイムスタンプ)
    payTimelong支払い成功時間(Unixタイムスタンプ)
    userIdintユーザーID
    refundStatusintはい返金ステータス。返金時に値がある:0:返金中、1:返金成功、2:返金失敗、3:返金拒否
    refundTimelongはい返金時間(Unixタイムスタンプ)。返金時に値がある

    リクエスト例:

    javascript
    {
        "gameId"9968,
        "orderId""zXhKYRy3genKKh9TgndBpu1gp5tBpA",
        "arrivedStatus"0,
        "productId""1002",
        "createTime"1755657098,
        "payTime"1755657115,
        "userId"278,
        "refundStatus"null,
        "refundTime"null
    }
    • 返却されるJSONオブジェクトには以下のフィールドが含まれます(code:200は成功):
    json
    {
        "code""200",
        "msg""Success"
    }
  • エラーコード:

    • 305 必須パラメータが空
    • 40001 対応するゲームが見つからない
    • 41007 検証失敗
    • 500 システムエラー
    *一般的な注意*
    • ゲームサーバーが200を返さない場合、支払いサービスは3時間後に最大5回再送します。
    • 支払い通知受信時にはパラメータ検証が必要です。検証方法は以下の通り:
    javascript
    public boolean verifySignature(String body, String authorizationHeader) throws Exception
    {
        if (authorizationHeader == null || !authorizationHeader.startsWith("Signature "))
        {
            throw new Exception("\"Authorization\" header not found or invalid in Jogos webhook request.");
        }
    
        String clientSignature = authorizationHeader.substring(10); // "Signature " をスキップ
        String serverSignature = sha1(body + your_key); // your_keyはゲーム特定の共有キー、ゲームパラメータで設定
    
        return clientSignature.equals(serverSignature);
    }

2. ゲームサーバーでの発送完了後、「到着ステータス更新」APIを呼び出し、注文を発送済みに設定

  • リクエストURL:[POST] https://api.jogos.com/api/gamepay/webhook/arrivedorder

  • リクエストヘッダ:

    フィールド名タイプ空許可説明
    Authorizationstring検証ヘッダ。sha1(body+キー)、キーはゲームの共有キー(ゲームパラメータで設定)
  • リクエストボディ: | フィールド名 | タイプ | 空許可 | 説

明 | | ------------ | ---- | ---- | ---- | | gameId | int | 否 | ゲームID | | orderId | int | 否 | 注文番号 |

リクエスト例:

javascript
{
    "gameId"9943,
    "orderId":"gHpGwweTlucXwcM6yIeSMcgKkhFmoO"
}
  • 返却JSONオブジェクト(code:200は成功):

    json
    {
        "code""200",
        "msg""Success"
    }
  • エラーコード:

    • 305 必須パラメータが空
    • 40001 対応するゲームが見つからない
    • 41007 検証失敗
    • 500 システムエラー

3. ゲームサーバーで注文リストを取得し、注文および到着ステータスを同期

  • リクエストURL:[POST] https://api.jogos.com/api/gamepay/getOrders

  • リクエストヘッダ:

    フィールド名タイプ空許可説明
    Authorizationstring検証ヘッダ。sha1(body+キー)、キーはゲームの共有キー(ゲームパラメータで設定)
  • リクエストボディ:

    フィールド名タイプ空許可説明
    gameIdintゲームID
    pageNointページ番号
    pageSizeintページサイズ

    リクエスト例:

    javascript
    {
        "gameId"9943,
        "pageNo":1
        "pageSize":20
    }
  • 返却JSONオブジェクト(code:200は成功):

    フィールド名タイプ空許可説明
    codeStringステータスコード (例: SUCCESS)
    messageStringメッセージ (例: ログアウト成功)
    totalInteger総件数
    pageSizeInteger1ページあたり件数
    currentPageInteger現在ページ
    totalPageInteger総ページ数
    orderIdString注文番号
    arrivedStatusInteger到着ステータス;0 未到着,1 到着済み
    payTimelong支払時間(Unixタイムスタンプ)
    productIdString商品ID
    userIdIntegerユーザーID
    refundStatusIntegerはい返金ステータス(返金時のみ値がある):0:返金中、1:返金成功、2:返金失敗、3:返金拒否
    refundTimelongはい返金時間(Unixタイムスタンプ)、返金時のみ値がある
    json
    {
      "code": "200",
      "msg": "Success",
      "page": {
        "total": 31,
        "totalPage": 7,
        "currentPage": 1,
        "pageSize": 5,
        "content": [
          {
            "orderId": "gHpGwweTlucXwcM6yIeSMcgKkhFmoO",
            "arrivedStatus": 1,
            "payTime": 1112211221,
            "productId": "game_pro1",
            "userId": 278,
            "refundStatus": null,
            "refundTime": null
          }
        ]
      }
    }
  • エラーコード:

    • 305 必須パラメータが空
    • 40001 対応するゲームが見つからない
    • 41007 検証失敗
    • 500 システムエラー

4. ユーザーが返金した場合、ゲームサーバーに返金成功通知を送信

  • Jogosプラットフォームは、ユーザーが返金申請を行い成功した注文のコールバック情報を、設定した コールバック通知URL に送信
  • リクエストボディは第1項「支払い成功通知」と同じ
  • 開発者は返金注文情報をもとに、プレイヤーが以前に得た報酬アイテムを適宜減算または制限することを推奨