数据推送

概述

数据推送是指在某个资源发生变化时,自动向订阅的应用发送变化相关的信息请求的功能。

配置

在开发者后台中,配置应用的订阅的地址、Token 和关注的资源。

  1. 推送地址:一个可访问的公网地址,推送的信息会通过 HTTP GET 请求发送到该地址。在正常的情况下,接口应返回 200 状态码。
  2. Token:一个字符串,用于参与验证推送请求的合法性。由开发者自行生成。
  3. 资源:开发者可以选择关注的资源,比如用户、权限等。

请求参数格式

请求方式:GET 请求参数:

参数名称 参数类型 参数说明
nonce string 随机字符串,用于签名
timestamp integer Unix 时间戳
signature string 签名信息
op string 操作类型,可能的值 updatedcreateddeleted
school_id integer 学校 ID
identity string 资源标识
type string 操作类型,
operated_at string 操作时间,格式为 2024-12-31 12:00:00

推送示例如下:

GET https://yourdomain.com/?nonce=9xmas123&timestamp=1713153015&signature=xxxx&&op=updated&school_id=1&identity=1&operated_at=2024-01-01 00:00:00

请求认证

为保证推送请求的合法性,我们在请求中加入了签名信息,开发者可以通过验证签名信息来判断请求的合法性。

签名信息的生成方式如下:

  1. 将请求参数按照参数名的字典序排序
    1. 参数包括:nonce, timestamp, op, school_id, identity, operated_at
    2. 注意参数 school_id 和 timestamp 需要转换为整型
  2. 将参数编码成 JSON 字段串
  3. 使用 HMAC-SHA256 算法,使用开发者配置的 Token 作为密钥,对 json 字段串进行签名
  4. 将签名信息加入到请求参数中

签名示例:

预定义的 Token 值:87892dedaf483eeabed6c54e4335fbe5 收到请求如下:

https://yourdomain.com/?identity=1&nonce=bfcf312b&op=created&operated_at=2024-04-15%2014%3A25%3A32&school_id=0&timestamp=1713162332&type=ping&signature=74b48b7a98c2fb8acbc99f41582390e98b535a4fa2e1b2fa33a1224aa8ff0220

校验签名方式如下:

PHP 版本示例

<?php
$token = '87892dedaf483eeabed6c54e4335fbe5';
$queryStr = 'identity=1&nonce=bfcf312b&op=created&operated_at=2024-04-15%2014%3A25%3A32&school_id=0&timestamp=1713162332&type=ping&signature=74b48b7a98c2fb8acbc99f41582390e98b535a4fa2e1b2fa33a1224aa8ff0220';

parse_str($queryStr, $query);

$signature = $query['signature'];
unset($query['signature']);

$query['school_id'] = (int)$query['school_id'];
$query['timestamp'] = (int)$query['timestamp'];

ksort($query);
$json = json_encode($query);
var_dump($json);
$hash = hash_hmac('sha256', $json, $token);
if ($hash === $signature) {
    echo '验证成功';
} else {
    echo '验证失败';
} 

// https://onlinephp.io/c/59c83d

Python 版本示例

import hashlib
import hmac
import json
from urllib.parse import parse_qs

token = '87892dedaf483eeabed6c54e4335fbe5'
query_str = 'identity=1&nonce=bfcf312b&op=created&operated_at=2024-04-15%2014%3A25%3A32&school_id=0&timestamp=1713162332&type=ping&signature=74b48b7a98c2fb8acbc99f41582390e98b535a4fa2e1b2fa33a1224aa8ff0220'

query_dict = parse_qs(query_str, keep_blank_values=True)
query = {k: v[0] for k, v in query_dict.items()}
signature = query['signature']
del query['signature']

query['school_id'] = int(query['school_id'])
query['timestamp'] = int(query['timestamp'])

sorted_query = dict(sorted(query.items()))
json_data = json.dumps(sorted_query, ensure_ascii=False, separators=(',', ':'))
print(json_data)

hash_value = hmac.new(token.encode(), json_data.encode(), hashlib.sha256).hexdigest()
if hash_value == signature:
    print('验证成功')
else:
    print('验证失败')

// https://www.online-python.com/B8Gdh9CpRX

响应

推送请求的响应应返回 200 状态码,响应 Body 不作要求。

results matching ""

    No results matching ""