在做一些api接口设计时候会遇到设置权限问题,比如我这个接口只有指定的用户才能访问。
很多时候api接口是属于无状态的,没办法获取session,就不能够用登录的机制去验证,那么
大概的思路是在请求包带上我们自己构造好的签名,这个签名必须满足下面几点:
a、唯一性,签名是唯一的,可验证目标用户
b、可变性,每次携带的签名必须是变化的
c、时效性,具有一定的时效,过期作废
d、完整性,能够对数据包进行验证,防止篡改
第一套方法:
0 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 |
<?php // 设置一个公钥(key)和私钥(secret),公钥用于区分用户,私钥加密数据,不能公开 $key = "c4ca4238a0b923820dcc509a6f75849b"; $secret = "28c8edde3d61a0411511d3b1866f0636"; // 待发送的数据包 $data = array( 'username' => 'abc@qq.com', 'sex' => '1', 'age' => '16', 'addr' => 'guangzhou', 'key' => $key, 'timestamp' => time(), ); // 获取sign function getSign($secret, $data) { // 对数组的值按key排序 ksort($data); // 生成url的形式 $params = http_build_query($data); // 生成sign $sign = md5($params . $secret); // $sign = sha1($params . $secret); return $sign; } // 发送的数据加上sign $data['sign'] = getSign($secret, $data); /** * 后台验证sign是否合法 * @param [type] $secret [description] * @param [type] $data [description] * @return [type] [description] */ function verifySign($secret, $data) { // 验证参数中是否有签名 if (!isset($data['sign']) || !$data['sign']) { echo '发送的数据签名不存在'; die(); } if (!isset($data['timestamp']) || !$data['timestamp']) { echo '发送的数据参数不合法'; die(); } // 验证请求, 10分钟失效 if (time() - $data['timestamp'] > 600) { echo '验证失效, 请重新发送请求'; die(); } $sign = $data['sign']; unset($data['sign']); ksort($data); $params = http_build_query($data); // $secret是通过key在api的数据库中查询得到 $sign2 = md5($params . $secret); // $sign2 = sha1($params . $secret); if ($sign == $sign2) { die('验证通过'); } else { die('请求不合法'); } } ?> |
第二套方法:
0 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 |
/** * 哈希验证签名 */ function hmacSign($array, $token) { if (isset($array['sign'])) { $orig_sign = $array['sign']; unset($array['sign']); } else { print_r([1000, '签名错误']); } ksort($array); $requestString = ''; foreach ($array as $k => $v) { $requestString .= $k . '=' . urlencode($v); } echo strtolower($requestString); ///// echo '<br>'; ///// $newSign = hash_hmac("md5", strtolower($requestString), $token); if ($orig_sign != $newSign) { print_r([1000, '签名错误.']); return FALSE; }else{ print_r([1000, '签名正确.']); return TRUE; } } /** * 生成哈希签名 */ function getSign($array, $token) { ksort($array); $requestString = ''; foreach ($array as $k => $v) { $requestString .= $k . '=' . urlencode($v); } echo strtolower($requestString); ///// echo '<br>'; ///// $newSign = hash_hmac("md5", strtolower($requestString), $token); return $newSign; } define('token', 'usdfsdfsdfsdfs'); $data = [ 'time' => 'F1523002001', 'DId' => '22320200012', 'appid' => '12547412589', 'info'=> serialize(['a'=>1,'b'=>2]) // 如子数组可以用序列化 ]; /** * 客户端 签名 */ $sign = getSign($data, token); $data['sign'] = $sign; echo '<pre>'; print_r($data); echo '</pre><br>'; echo "\$sign=$sign"; ///// echo '<br>'; ///// /** * 服务器验证 */ // $sig = $data; // $sig['sign'] = '747f5a7a58e0c9baf92c29315cf8de44'; $verify = hmacSign($data, token); echo "\$verify=$verify"; ///// |