Hướng dẫn tích hợp giao diện máy chủ
Nếu trò chơi của bạn có máy chủ riêng và dữ liệu người chơi được lưu trữ, quản lý bởi máy chủ của bạn, bạn cần tích hợp máy chủ như sau:
Module | Mô tả | Khuyến nghị tích hợp |
---|---|---|
Hệ thống người dùng | Bạn cần liên kết hệ thống người dùng của Jogos với người dùng trên máy chủ của bạn, cần tích hợp từ phía máy chủ | ☑️ Cần thiết |
Hệ thống mua hàng trong ứng dụng | Nếu trò chơi của bạn có các mục mua trong ứng dụng, cần tích hợp hệ thống mua hàng của Jogos để đảm bảo thanh toán và bảo mật dữ liệu | ☑️ Cần thiết cho trò chơi có mua hàng |
Tích hợp hệ thống người dùng
1. Lấy token người dùng từ phía client
- Vui lòng tham khảo trước:
SDK tích hợp người dùng phía client
.
2. Tổng quan
Sau khi nhận token người dùng và publickey từ Jogos, gửi về máy chủ trò chơi để xác thực và lấy thông tin người dùng. Lưu ý: mỗi lần xác thực token đều phải lấy publickey vì nó có thể thay đổi bất cứ lúc nào.
3. Logic xác thực
- Nhà phát triển trò chơi lấy token người dùng từ Jogos và gửi về máy chủ của mình.
- Máy chủ lấy publickey (thông qua https://www.jogos.com/publicKey.json).
- Chuyển chuỗi publickey mã hóa Base64 thành khóa công khai RSA.
- Sử dụng khóa RSA để giải mã JWT token. Token đã giải mã có thể kiểm tra trên jwt.io.
- Sau khi giải mã, lấy thông tin người dùng và liên kết với người dùng trên máy chủ trò chơi.
- Nếu giải mã thất bại, trả về thông tin người dùng rỗng.
4. Ví dụ code
Thêm thư viện jwt vào project:
<!--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) {
/**
* Lấy publickey và token người dùng từ Jogos SDK và gửi về server, ví dụ publickey:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhyUrr/W8bSuC+HK8Rk++BDOGDefGMEBa9jekVwVE3oeqi7QbVzZPAuqb1K3GPJjDBfi44IWzb3w8Xa0P1ZeO2Cnbg1LltanlzFv/EcKseCIkOd8Qo78ARPfmlf4WP6MznYGKwNVGFh/s5Y6ar8QgWX1ttkcwYzHu/gUroO+nPOZkU6bfxHjRrJxk3lSQBZWfTSFd2JFwntq3h45UHymjQZiMtW47G2C4VTtTTt1Iz0VQ9rdtWie/+REqQYoFUm04Yns9jyG3TZzio9vsRrxESLQbBIRxto77cQNtEe9j/2EXNwQabRkiS6zo6i2TIN4O6uthWBVud5WXsBWdiyIOHQIDAQAB
-----END PUBLIC KEY-----
và token người dùng:
eyJhbGciOiJSUzI1NiJ9.eyJqdGkiOiIxOTY3NDIzNTM3NjE1NTgxMTg0Iiwic3ViIjoie1wicHJvZmlsZVBpY3R1cmVVcmxcIjpcImh0dHBzOi8vaW1hZ2Uuam9nb3NwcmUuY29tLzBlZTkyZjViZTRhMzQ4NzBhYjY0YWU1N2FjN2I1YmE0LmpwZ1wiLFwiZ2FtZUlkXCI6XCIxMjIwXCIsXCJ1c2VySWRcIjpcIjI1N1wiLFwidXNlcm5hbWVcIjpcIlBsYXllcjI1N1wifSIsImlzcyI6ImNvbTpqb2dvczpzZGsiLCJpYXQiOjE3NTc5MDUyOTgsImV4cCI6MTc2MTUwNTI5OH0.MKBab0XC1o5AYGosbq1l5m9xCLN1-4xfcr7_dHn-_C8Eh2moTuq9TbQutIajB3dViFW0e1KyIg7UhxNk00rdhT2b5UrvO23tyFsgg9FYyAyCZABURxHyI0lTW9V8YA9k4faycK_gCUMXH_IubseDMz1P7cYmPpo8WxJXZq3R-mL8OhhuKCn8DlpP5BVsd0_gYSTvDUD0gjdINLUNTVrZVkETcDVWW8OXQVzJxdTH0VVlDs4cGvIyko8TJ6g1Bvz4VWj4qy1XoQFfRBH8sgBl3oGJtUodhq3b4bOx4Cr_o-2tK54CetDdmmCPbtcbmmDcBqK5EQ51A2Kws-1cYtsFxg
Lưu ý: mỗi lần xác thực token đều phải lấy publickey vì nó có thể thay đổi
*/
String publickey ="publickey của bạn";
String token = "token người dùng của bạn";
System.out.println("publickey:["+publickey+"]");
System.out.println("token:["+token+"]");
Map<String, Object> userMap = verifyToken(token,publickey);
// Nếu token giải mã thành công, userMap không rỗng
if (userMap != null) {
System.out.println("Xác thực thành công, thông tin người dùng:");
System.out.println(JSONObject.toJSONString(userMap));
}else {
System.out.println("Xác thực JWT thất bại");
}
}
/**
* Xác thực token
* @param token
* @return
*/
public static Map<String, Object> verifyToken(String token,String publickey){
// Thử giải mã token, nếu thất bại trả về null
Map<String, Object> map = null;
try {
map = parseToken(token,publickey);
} catch (Exception e) {
}
return map;
}
/**
* Giải mã token
* @param token
* @return
*/
public static Map<String,Object> parseToken(String token,String publickey){
// Loại bỏ phần đầu và cuối
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;
}
/**
* Chuyển chuỗi Base64 thành RSA public key
* @param key Chuỗi public key mã hóa Base64
* @return Khóa RSA công khai
* <p>
* Lưu ý: Phương thức này sử dụng Base64 decoder để giải mã thành mảng byte, sau đó sử dụng KeyFactory và X509EncodedKeySpec
* để chuyển byte array thành đối tượng PublicKey. Nếu xảy ra lỗi sẽ ném 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;
}
}
Tích hợp hệ thống mua hàng trong ứng dụng
Trước khi bắt đầu:
Xác nhận bạn đang dùng
www.jogospre.com
(môi trường test) hoặcwww.jogos.com
(môi trường production); các URL POST dưới đây phải thay bằng địa chỉ tương ứng (ví dụ API test về hàng: https://api.jogospre.com/api/gamepay/webhook/arrivedorder)Đảm bảo bạn đã tạo trò chơi trên Developer Platform và đã tạo Shared Key trong “Game Parameters”.
Đảm bảo trò chơi của bạn bật chế độ “Mua trong ứng dụng” và nhập địa chỉ callback của server.
Giao tiếp sử dụng SHA-1, ví dụ:
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); } }
Tích hợp phía client:
- Client tạo đơn hàng và khởi tạo thanh toán.
- Tham khảo
SDK mua hàng trong ứng dụng phía client
.
Tích hợp phía server:
1. Khi người dùng mua thành công, Jogos gửi thông báo thanh toán thành công
Jogos gửi callback về địa chỉ callback đã cấu hình.
Header:
Tên trường Loại Có thể trống Mô tả Authorization string Không Header xác thực, sha1(body+shared_key), shared_key là key của trò chơi Body chứa các trường:
Tên trường Loại Có thể trống Mô tả paytype String Không Loại thông báo: pay = thanh toán thành công; refund = hoàn tiền thành công gameId int Không ID trò chơi orderId String Không Mã đơn hàng arrivedStatus int Không Trạng thái nhận hàng: 0 = chưa nhận, 1 = đã nhận productId String Không ID sản phẩm createTime long Không Thời gian tạo đơn (Unix timestamp) payTime long Không Thời gian thanh toán thành công (Unix timestamp) userId int Không ID người dùng refundStatus int Có Trạng thái hoàn tiền: 0=đang hoàn,1=thành công,2=thất bại,3=bị từ chối refundTime long Có Thời gian hoàn tiền (Unix timestamp) Ví dụ body:
javascript{ "gameId": 9968, "orderId": "zXhKYRy3genKKh9TgndBpu1gp5tBpA", "arrivedStatus": 0, "productId": "1002", "createTime": 1755657098, "payTime": 1755657115, "userId": 278, "refundStatus": null, "refundTime": null }
- Response JSON:
json{ "code": "200", "msg": "Success" }
Mã lỗi:
305
Tham số bắt buộc trống40001
Không tìm thấy trò chơi41007
Xác thực thất bại500
Lỗi hệ thống
2. Khi server trò chơi giao hàng xong, gọi API “Cập nhật trạng thái nhận hàng”
URL: [POST] https://api.jogos.com/api/gamepay/webhook/arrivedorder
Header:
Tên trường Loại Có thể trống Mô tả Authorization string Không Header xác thực, sha1(body+shared_key) Body:
Tên trường Loại Có thể trống Mô tả gameId int Không ID trò chơi orderId int Không Mã đơn hàng Ví dụ body:
javascript{ "gameId": 9943, "orderId":"gHpGwweTlucXwcM6yIeSMcgKkhFmoO" }
Response JSON:
json{ "code": "200", "msg": "Success" }
Mã lỗi:
305
Tham số bắt buộc trống40001
Không tìm thấy trò chơi41007
Xác thực thất bại500
Lỗi hệ thống
3. Server trò chơi truy vấn danh sách đơn hàng và đồng bộ trạng thái nhận hàng
URL: [POST] https://api.jogos.com/api/gamepay/getOrders
Header:
Tên trường Loại Có thể trống Mô tả Authorization string Không Header xác thực, sha1(body+shared_key) Body:
Tên trường Loại Có thể trống Mô tả gameId int Không ID trò chơi pageNo int Không Số trang pageSize int Không Số mục mỗi trang Ví dụ body:
javascript{ "gameId": 9943, "pageNo":1, "pageSize":20 }
Response JSON (code:200 = thành công):
| Tên trường | Loại | Có thể trống | Mô tả |
| ------------- | ------- | ------------ | ----- | | code | String | Không | Mã trạng thái (ví dụ: SUCCESS) | | message | String | Không | Thông báo (ví dụ: Đăng xuất thành công) | | total | Integer | Không | Tổng số | | pageSize | Integer | Không | Số mục mỗi trang | | currentPage | Integer | Không | Trang hiện tại | | totalPage | Integer | Không | Tổng số trang | | orderId | String | Không | Mã đơn hàng | | arrivedStatus | Integer | Không | Trạng thái nhận hàng: 0 chưa nhận, 1 đã nhận | | payTime | long | Không | Thời gian thanh toán (Unix timestamp) | | productId | String | Không | ID sản phẩm | | userId | Integer | Không | ID người dùng | | refundStatus | Integer | Có | Trạng thái hoàn tiền: 0=đang hoàn,1=thành công,2=thất bại,3=bị từ chối | | refundTime | long | Có | Thời gian hoàn tiền (Unix timestamp) |
{
"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
}
]
}
}
Mã lỗi:
305
Tham số bắt buộc trống40001
Không tìm thấy trò chơi41007
Xác thực thất bại500
Lỗi hệ thống
4. Khi người dùng hoàn tiền, gửi thông báo về server trò chơi
- Jogos gửi callback về địa chỉ callback cho đơn hàng hoàn tiền thành công.
- Body giống với thông báo “Thanh toán thành công”.
- Khuyến nghị nhà phát triển căn cứ thông tin đơn hoàn tiền để giảm hoặc hạn chế các vật phẩm đã được người chơi nhận từ lần nạp trước.