Description des interfaces d'intégration côté serveur
Si votre jeu possède son propre serveur de jeu et que les données des joueurs sont conservées et gérées par votre serveur, une intégration côté serveur est nécessaire :
Module | Description | Suggestion d'intégration |
---|---|---|
Système utilisateur | Vous devez associer le système utilisateur de la plateforme Jogos à vos utilisateurs serveur. Cela nécessite une intégration côté serveur du système utilisateur | ☑️ Intégration nécessaire |
Système d'achats intégrés | Si votre jeu comporte des achats intégrés, vous devez intégrer le système d'achats intégrés de Jogos pour garantir la sécurité des paiements et des données des utilisateurs | ☑️ Intégration nécessaire pour les jeux avec achats intégrés |
Intégration du système utilisateur
1 Obtention du token utilisateur via le client
- Veuillez d'abord consulter :
Intégration client du SDK utilisateur
.
2 Aperçu
Après avoir obtenu le token utilisateur et la clé publique depuis Jogos, renvoyez-les à votre serveur de jeu pour vérification et récupération des informations utilisateur. Attention : récupérez la clé publique à chaque vérification de token, car elle peut changer à tout moment.
3 Logique de vérification
- Le développeur du jeu obtient le token utilisateur depuis Jogos et le renvoie au serveur du jeu.
- Le serveur récupère ensuite la clé publique (via https://www.jogos.com/publicKey.json).
- Convertir la clé publique Base64 en clé publique RSA.
- Décrypter le token JWT avec la clé RSA. Le décryptage peut être testé sur jwt.io.
- Après décodage, récupérer les informations utilisateur et les associer à vos utilisateurs serveur.
- Si le décryptage échoue, retourner des informations utilisateur vides.
4 Exemple de code
Ajouter JWT dans le projet :
<!--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>
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) {
/**
* Obtenez la clé publique et le token utilisateur depuis le SDK Jogos et envoyez-les au serveur, par exemple :
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhyUrr/W8bSuC+HK8Rk++BDOGDefGMEBa9jekVwVE3oeqi7QbVzZPAuqb1K3GPJjDBfi44IWzb3w8Xa0P1ZeO2Cnbg1LltanlzFv/EcKseCIkOd8Qo78ARPfmlf4WP6MznYGKwNVGFh/s5Y6ar8QgWX1ttkcwYzHu/gUroO+nPOZkU6bfxHjRrJxk3lSQBZWfTSFd2JFwntq3h45UHymjQZiMtW47G2C4VTtTTt1Iz0VQ9rdtWie/+REqQYoFUm04Yns9jyG3TZzio9vsRrxESLQbBIRxto77cQNtEe9j/2EXNwQabRkiS6zo6i2TIN4O6uthWBVud5WXsBWdiyIOHQIDAQAB
-----END PUBLIC KEY-----
et le token utilisateur :
eyJhbGciOiJSUzI1NiJ9.eyJqdGkiOiIxOTY3NDIzNTM3NjE1NTgxMTg0Iiwic3ViIjoie1wicHJvZmlsZVBpY3R1cmVVcmxcIjpcImh0dHBzOi8vaW1hZ2Uuam9nb3NwcmUuY29tLzBlZTkyZjViZTRhMzQ4NzBhYjY0YWU1N2FjN2I1YmE0LmpwZ1wiLFwiZ2FtZUlkXCI6XCIxMjIwXCIsXCJ1c2VySWRcIjpcIjI1N1wiLFwidXNlcm5hbWVcIjpcIlBsYXllcjI1N1wifSIsImlzcyI6ImNvbTpqb2dvczpzZGsiLCJpYXQiOjE3NTc5MDUyOTgsImV4cCI6MTc2MTUwNTI5OH0.MKBab0XC1o5AYGosbq1l5m9xCLN1-4xfcr7_dHn-_C8Eh2moTuq9TbQutIajB3dViFW0e1KyIg7UhxNk00rdhT2b5UrvO23tyFsgg9FYyAyCZABURxHyI0lTW9V8YA9k4faycK_gCUMXH_IubseDMz1P7cYmPpo8WxJXZq3R-mL8OhhuKCn8DlpP5BVsd0_gYSTvDUD0gjdINLUNTVrZVkETcDVWW8OXQVzJxdTH0VVlDs4cGvIyko8TJ6g1Bvz4VWj4qy1XoQFfRBH8sgBl3oGJtUodhq3b4bOx4Cr_o-2tK54CetDdmmCPbtcbmmDcBqK5EQ51A2Kws-1cYtsFxg
Remarque : récupérez la clé publique à chaque vérification de token, car elle peut changer.
*/
String publickey ="Votre clé publique";
String token = "Votre token utilisateur";
System.out.println("publickey:["+publickey+"]");
System.out.println("token:["+token+"]");
Map<String, Object> userMap = verifyToken(token,publickey);
// Si le token est analysé avec succès, userMap n'est pas vide
if (userMap != null) {
System.out.println("Vérification réussie, informations utilisateur :");
System.out.println(JSONObject.toJSONString(userMap));
}else {
System.out.println("Échec de la vérification JWT");
}
}
/**
* Vérification du token
* @param token
* @return
*/
public static Map<String, Object> verifyToken(String token,String publickey){
// Essayer de parser le token, si échec retourner null
Map<String, Object> map = null;
try {
map = parseToken(token,publickey);
} catch (Exception e) {
}
return map;
}
/**
* Décryptage du token
* @param token
* @return
*/
public static Map<String,Object> parseToken(String token,String publickey){
// Supprimer les en-têtes et pieds
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;
}
/**
* Obtenir la clé publique RSA depuis une chaîne Base64
* @param key Chaîne Base64 de la clé publique
* @return Clé publique RSA
* <p>
* Remarque : cette méthode décode la chaîne en tableau d'octets via Base64, puis utilise KeyFactory et X509EncodedKeySpec
* pour convertir le tableau d'octets en objet PublicKey. En cas d'exception, une RuntimeException est levée.
*/
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;
}
}
Intégration du système d'achats intégrés
Avant de commencer l'intégration, assurez-vous de :
Utiliser
www.jogospre.com
(environnement de test) ouwww.jogos.com
(environnement de production) ; les URL POST ci-dessous doivent être adaptées en conséquence. (Par exemple, l'API de test : https://api.jogospre.com/api/gamepay/webhook/arrivedorder)Avoir créé l'application de jeu sur la plateforme développeur et généré la clé partagée dans les paramètres du jeu.
Avoir activé le mode “Achats intégrés” dans les options de votre jeu et renseigné l'URL de callback serveur.
La communication utilise un chiffrement SHA-1, exemple d'utilisation :
javascriptprivate 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); } }
Intégration côté client :
- Créer et initier les commandes via le client.
- Veuillez consulter :
Intégration client du SDK paiement
.
Intégration côté serveur :
1. Notification de paiement réussi après achat dans le jeu
La plateforme Jogos envoie la notification de paiement réussi à l'URL de callback configurée.
En-têtes de requête :
Nom du champ Type Obligatoire Description Authorization string Oui En-tête de validation, sha1(body+clé), où la clé est la clé partagée du jeu Corps de la requête :
Nom du champ Type Obligatoire Description paytype String Oui Type de notification : pay = paiement réussi ; refund = remboursement réussi gameId int Oui ID du jeu orderId String Oui Numéro de commande arrivedStatus int Oui Statut de livraison : 0 non livré, 1 livré productId String Oui ID du produit createTime long Oui Date de création de la commande (timestamp Unix) payTime long Oui Date de paiement réussi (timestamp Unix) userId int Oui ID utilisateur refundStatus int Non Statut de remboursement : 0 en cours, 1 réussi, 2 échoué, 3 refusé refundTime long Non Date du remboursement (timestamp Unix), si applicable Exemple de corps de requête :
javascript{ "gameId": 9968, "orderId": "zXhKYRy3genKKh9TgndBpu1gp5tBpA", "arrivedStatus": 0, "productId": "1002", "createTime": 1755657098, "payTime": 1755657115, "userId": 278, "refundStatus": null, "refundTime": null }
Réponse JSON (code 200 = succès) :
json{ "code": "200", "msg": "Success" }
Codes d'erreur :
305
Paramètre obligatoire manquant40001
Jeu non trouvé41007
Vérification échouée500
Erreur système
2. Mise à jour du statut de livraison côté serveur après traitement de la commande
URL de requête : [POST] https://api.jogos.com/api/gamepay/webhook/arrivedorder
En-têtes de requête :
Nom du champ Type Obligatoire Description Authorization string Oui En-tête de validation, sha1(body+clé), où la clé est la clé partagée du jeu Corps de requête :
Nom du champ Type Obligatoire Description gameId int Oui ID du jeu orderId int Oui Numéro de commande Exemple :
javascript{ "gameId": 9943, "orderId":"gHpGwweTlucXwcM6yIeSMcgKkhFmoO" }
Réponse JSON (code 200 = succès) :
json{ "code": "200", "msg": "Success" }
Codes d'erreur :
305
Paramètre obligatoire manquant40001
Jeu non trouvé41007
Vérification échouée500
Erreur système
3. Consultation des commandes côté serveur et synchronisation du statut de livraison
URL : [POST] https://api.jogos.com/api/gamepay/getOrders
En-têtes de requête :
Nom du champ Type Obligatoire Description Authorization string Oui En-tête de validation, sha1(body+clé), où la clé est la clé partagée du jeu Corps de requête :
Nom du champ Type Obligatoire Description gameId int Oui ID du jeu pageNo int Oui Numéro de page pageSize int Oui Nombre d'éléments par page Exemple :
javascript{ "
gameId": 9943, "pageNo":1, "pageSize":20 }
- Réponse JSON (code 200 = succès) :
| Nom du champ | Type | Obligatoire | Description |
| ---------------- | ------- | ----------- | ----------- |
| code | String | Oui | Code de statut (ex : SUCCESS) |
| message | String | Oui | Message d'information (ex : Déconnexion réussie) |
| total | Integer | Oui | Nombre total |
| pageSize | Integer | Oui | Nombre par page |
| currentPage | Integer | Oui | Page actuelle |
| totalPage | Integer | Oui | Nombre total de pages |
| orderId | String | Oui | Numéro de commande |
| arrivedStatus | Integer | Oui | Statut de livraison : 0 non livré, 1 livré |
| payTime | long | Oui | Heure de paiement (timestamp Unix) |
| productId | String | Oui | ID du produit |
| userId | Integer | Oui | ID utilisateur |
| refundStatus | Integer | Non | Statut remboursement si applicable : 0 en cours, 1 réussi, 2 échoué, 3 refusé |
| refundTime | long | Non | Timestamp remboursement si applicable |
```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
}
]
}
}
Codes d'erreur :
305
Paramètre obligatoire manquant40001
Jeu non trouvé41007
Vérification échouée500
Erreur système
4. Notification de remboursement côté serveur
- La plateforme Jogos envoie les notifications de remboursement à l'URL de callback configurée.
- Le corps de la requête est identique à celui de la notification de paiement réussi.
- Il est recommandé de déduire ou limiter les récompenses obtenues précédemment par l'utilisateur lors d'un remboursement.
Ce document est entièrement prêt à être utilisé en Markdown dans VSCode, avec **tous les conteneurs, en-têtes, code blocks et syntaxes conservés**.
Si tu veux, je peux aussi préparer une **version PDF ou Word technique** formatée à partir de ce Markdown, pratique pour les équipes de dev. Veux-tu que je fasse ça ?