游戏服务端接入指引

玩家token有效性检查接口

请求地址

请求协议

  • http POST
  • Content-Type: application/json
  • Accept: application/json

请求参数

参数 必传 类型 含义
app_id Yes string yofun给游戏分配的app_id
user_id Yes string 登录成功后,yofun返回给游戏的user_id
channel_token Yes string sdk返给游戏的token

返回值

参数 类型 含义
code int 响应码
    当成功返回,即状态码为200时,无此项,仅在出现错误时才有.
msg string 响应提示

响应码说明:

含义
1001 无效的参数和格式
4001 用户凭证过期

订单支付成功回调接口

接口描述

接入SDK的游戏,在客户端创建订单接口时传入对应的回调接口地址。用户支付成功后,游戏服务器通过这个接口接收支付成功的订单信息。

请求协议

  • http POST
  • Content-Type: application/json
  • Accept: application/json

请求参数

Http请求头包含以下字段:

参数 必传 类型 含义
X-Param-Sign Yes string 使用网易私钥签名,游戏需使用网易提供的公钥进行验签。

Http请求体为json对象,字段描述如下:

参数 类型 含义
order_id string sdk订单号
game_order_id string app订单号
app_id string 游戏编号
user_id string yofun用户id
status int 订单状态: 1初始化;2成功;3失败; 理论上成功才会通知
order_price int 订单金额 单位分
goods_info json 商品信息 字典格式(dict)
create_time int 订单创建时间 Unix时间戳(Unix timestamp)精确到秒
pay_time int 订单支付完成时间 Unix时间戳(Unix timestamp)精确到秒
pay_method string 支付方式 例如支付宝、银联、平台币等
reserved string 透传字段 客户端创建的时候传入

返回值

返回值为json格式,字段描述如下:

参数 类型 含义
code int 状态码
msg string 描述信息

code 含义如下:

code msg 中文描述
200 success 成功,不再通知
201 duplicate 重复通知,不再通知
500 other error 其它错误,继续通知

失败重试机制

游戏服务器在收到支付成功的通知后,如果没有返回200给SDK服务器,SDK服务器会认为游戏服务器没有收到通知,并重复通知直至成功,或者超时(24小时)。

请求示例

  • 请求地址示例(游戏服务端提供):

    http://{apphost}:{port}/notify?someother=xxx
    
  • Body

    {
        "order_id": 1194,
        "game_order_id": "hub_test_1542167165",
        "app_id": "mumu",
        "user_id": "aebvxkqr6uaaaadm",
        "status": 2,
        "order_price": 1,
        "goods_info": "{\"goods_id\": \"product_01\", \"goods_name\": \"好吃的ddd\", \"goods_count\": 1, \"goods_price\": 1}",
        "create_time": 1542167166,
        "pay_time": 1542167171,
        "pay_method": "ALIPAY"
        "reserved": "{\"key3\": \"value3\", \"key2\": \"value2\", \"key1\": \"value1\"}",
    }
    
  • 签名公钥:

    平台提供, 签名方式SHA1RSA

  • 签名原文:url+body

    sign = sha1rsa(PATH_QS+BODY) PATH_QS 为URL中除请求协议以及域名端口之外的部分,如/notify?someother=xxx

    注意:如果回调地址本身没有带参数,只是url,也需要加上?号做拼接

  • 待签名串:

    /notify?someother=xxx{
        "order_id": 1194,
        "game_order_id": "hub_test_1542167165",
        "app_id": "mumu",
        "user_id": "aebvxkqr6uaaaadm",
        "status": 2,
        "order_price": 1,
        "goods_info": "{\"goods_id\": \"product_01\", \"goods_name\": \"好吃的ddd\", \"goods_count\": 1, \"goods_price\": 1}",
        "create_time": 1542167166,
        "pay_time": 1542167171,
        "pay_method": "ALIPAY"
        "reserved": "{\"key3\": \"value3\", \"key2\": \"value2\", \"key1\": \"value1\"}",
    }
    
  • 签名(注意是16进制):

    95b95cefb164085bd7f2acaeb6088986e75b641741b560dfea4e3d8e4e30d4a773f7d5744b65eefdb74e42ccd3f3bacab7a2fc8c40584424495bbd4898eae5baaf0e42a98ac01267b8c567af653fae76c0d6e37a120f5c6d276f636dea3a3fdb733e489c6a90a5db41bbfb6c3e15ac758d2af805a395679a003635ec9561a73d
    
  • Http Header:

    X-Param-Sign: 95b95cefb164085bd7f2acaeb6088986e75b641741b560dfea4e3d8e4e30d4a773f7d5744b65eefdb74e42ccd3f3bacab7a2fc8c40584424495bbd4898eae5baaf0e42a98ac01267b8c567af653fae76c0d6e37a120f5c6d276f636dea3a3fdb733e489c6a90a5db41bbfb6c3e15ac758d2af805a395679a003635ec9561a73d
    
  • 游戏服务器验证订单的准确性之后返回:

    {
        "code": 200,
        "msg": "ok",
    }
    

签名Demo:

  • 原文:QueryString+body, QueryString是带有?的,即使回调接口没有参数,也需要带上? 如: /callback/yofun?{xxxxx}

  • 获取body内容,签名原文拼接切记直接将body拿来拼接,不要转成json再转回来,否则顺序就会被改变。

  • JAVA

    //验签
    public boolean verify(String plain, String signature,String keycode) {
        //获取公钥
        try {
            KeyFactory keyFactory= KeyFactory.getInstance("RSA");
            // 如果 Base64.decodeBase64() 需要以 byte[] 为参数,则需要将 keycode 转为 byte[],比如 keycode.getBytes()
            byte[] keyByte= Base64.decodeBase64(keycode);
            X509EncodedKeySpec encodeRule=new X509EncodedKeySpec(keyByte);
            PublicKey publicKey= keyFactory.generatePublic(encodeRule);
    
            Signature sign=Signature.getInstance("SHA1WithRSA");
            sign.initVerify(publicKey);
            sign.update(plain.getBytes());
    
            //将16进制码转成字符数组
            //注意这里是hex的
            byte[] hexByte= Hex.decodeHex(signature.toCharArray());
            //验证签名
            return sign.verify(hexByte);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }
    
    //获取body
    public static String readData(HttpServletRequest request) {
        BufferedReader br = null;
        try {
            StringBuilder ret;
            br = request.getReader();
    
            String line = br.readLine();
            if (line != null) {
            ret = new StringBuilder();
            ret.append(line);
            } else {
            return "";
            }
    
            while ((line = br.readLine()) != null) {
            ret.append('\n').append(line);
            }
    
            return ret.toString();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        finally {
            if (br != null) {
                try {br.close();} catch (IOException e) { e.printStackTrace();}
            }
        }
    }
    
  • PHP

    //plain=url+body
    function verify($plain, $sign, $pubKey) {
        $openssl_public_key = openssl_get_publickey($pubkey);
        //注意这里是hex2bin
        $ok = openssl_verify($plain, hex2bin('sign'), $openssl_public_key, OPENSSL_ALGO_SHA1);
        openssl_free_key($openssl_public_key);
    
        return $ok;
    }