一个简单的API授权流程

实际项目中我们经常会碰到给第三方开放我们项目API的这种场景。这时我们要保证api的安全,参考腾讯广点通的api调用。现将php的代码实现整理这此。

我们的算法很简单:

  1. 把调用方自己的appid,secret_key,当前的时间戳time连接起来用sha1方法生成一个sign
  2. 把appid,time,sign用英文逗号连接并用base64打包变成一个参数token

API的几个方法

api_functions.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
<?php
/**
* 生成token
* @param string $appid
* @param string $secret_key
* @param int $time
* @return string
*/
function generate_token($appid, $secret_key, $time)
{
$sign = sha1($appid . $secret_key . $time);
return base64_encode($appid . ',' . $time . ',' . $sign);
}

/**
* 解包token
* @param string $token
* @return array
*/
function unpack_token($token){
$params = base64_decode($token);
$params = explode(',', $params);

return [
'appid'=> isset($params[0]) ? $params[0] : '',
'time'=> isset($params[1]) ? $params[1] : '',
'sign'=> isset($params[2]) ? $params[2] : '',
];
}

/**
* @param $url
* @param array $data
* @param bool $is_post
* @param array $header
* @return mixed
*/
function sub_curl($url, $data = array(), $is_post = false, $header = array())
{
$ch = curl_init();
if (!$is_post && !empty($data)) {
$url = $url . '?' . http_build_query($data);
}
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, $is_post);
if ($is_post) {
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
}
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 20);
if (!empty($header)) {
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
}
$info = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if($code != 200){

echo_json($code, 'api调用出错'.$code);
}
curl_close($ch);
return $info;
}

/**
* @param int $code
* @param string $msg
* @param array $data
*/
function echo_json($code, $msg = '', $data = array()){
header('Content-type:application/json');
echo json_encode(array('ret' => $code, 'msg' => $msg, 'data' => $data));
exit;
}

API提供方

api.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
<?php
require 'api_functions.php';

//授权的使用方名单 现为演示方便直接使用数组
$users = [
'user_001'=>[
'appid'=>'user_001', //使用方对于提供方api的唯一id
'secret_key'=>'97bc847d4ea7dd9f035d41a657302f1c' //密钥 也唯一
],
'user_002'=>[
'appid'=>'user_002',
'secret_key'=>'c763b64a62186ae6831edd22063539c4'
],
'user_003'=>[
'appid'=>'user_003',
'secret_key'=>'51a683bea5e5c138fd0342fb70e03c65'
],
];

//检验签名
$token = isset($_GET['token']) ? trim($_GET['token']) : '';
if(empty($token)){
echo_json(1000, 'token missed');
}

//解包token
$token_params = unpack_token($token);

if(empty($token_params['sign'])){
echo_json(1001, 'sign error'); //签名为空或者错误
}

if(empty($token_params['appid'])){
echo_json(1002, 'appid error'); //appid为空或者错误
}

if(empty($token_params['time'])){
echo_json(1003, 'time error'); //time为空或者错误
}

if(abs($token_params['time'] - time()) > 10 * 60){ // api 调用时间限制左右浮动10分钟
echo_json(1004, 'time expired'); // 10 minutes
}

//用appid取用户
$user = isset($users[$token_params['appid']]) ? $users[$token_params['appid']] : [];
if(empty($user)){
echo_json(1005, 'appid not exists'); //调用方不存在
}

//使用调用方参数生成token
$create_token = generate_token($user['appid'], $user['secret_key'], $token_params['time']);

if($token !== $create_token){
echo_json(1006, 'token error'); //token错误
}

//到此 调用权限的验证就ok了

$api = isset($_GET['api']) ? trim($_GET['api']) : '';

//接下来你可以有其他对具体接口的验证...


//返回结果
echo_json(200, 'your request api '.$api. ' success!');

API调用方

use_api.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<?php
require 'api_functions.php';

//假设使用方是 user_001 他拥有自己的appid和secret_key
$user = [
'appid' => 'user_001', //使用方对于提供方api的唯一id
'secret_key' => '97bc847d4ea7dd9f035d41a657302f1c' //密钥 也唯一

];

//生成token
$token = generate_token($user['appid'], $user['secret_key'], time());

//url换成你自己的接口url
$url = 'http://' . $_SERVER['HTTP_HOST'] . dirname($_SERVER['REQUEST_URI']);

$url .= '/api.php?api=user_info'; //调用user_info的接口
$url .= '&token=' . $token;

echo $url;
echo '<hr><pre>';

//请求接口
$res = sub_curl($url);

var_dump(json_decode($res, 1));

/* 调用成功结果
array(3) {
["ret"]=>
int(200)
["msg"]=>
string(35) "your request api user_info success!"
["data"]=>
array(0) {
}
}
*/
打赏
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!

请我喝杯咖啡吧~

支付宝
微信