标签:
最近工作中有个笑脸需求。关于上海市食药监局对于餐厅食品安全评级的。简单些就是,第三方外卖公司等,需要调用他们的接口,获取餐厅评级,在自家网站上展示出来。大概是下面过程:
1) 提交第三方认证信息,取得Token;
2) 取得Token成功后,加入到Authorization header进行正常的业务接口调用;
3) Token还在有效期内,继续上述步骤,如果Token已失效,回到步骤1。
看起来是个挺简单的,发送自己的认证信息,调接口获取就ok。可是仔细看看他们的文档,提交的第三方认证信息需要一个加密过程。对php加密不是很了解,所以犯难了。
先看看第三方认证信息吧。
名称 |
说明 |
id |
第三方标识 |
name |
第三方名称 |
password |
密码 |
website |
第三方网站地址 |
这些都是公司相关认证信息。对以上信息需要进行如下加密:
1) 用使用者信息,及随机生成的GUID组成的JSON字符串作明文
例:
{
“id”:”xx”,
“name”:”XX”,
“website”:”www.XX.com”,
“gkey”:”379043FD-7335-40F6-874D-9FCFC6F84B42”
}
2) 用AES方法加密上述明文
AES加密时的参数选择,加密模式:CBC;填充模式:PKCS7。
加密时用的IV与密钥是基于当前日期、密码及一些使用者信息生成。
初始化向量(IV)通过如下方式得到:
密钥由下面方法得到:
3) 上一步加密得到的byte数组转成base64编码的字符串
4) 字符串进行URL编码
网上关于AES的加密代码很多,可没有接触过php的mcrypt加密的我来说,还是遇到了一些小坑。现在详细说下实现方式。
第一步。是要加密的明文。没有用到过GUID的小伙伴,可能会困惑。其实只是一个随机字符串。生成方式如下:
public function createGuid() { $charid = md5(uniqid(mt_rand(), true)); $hyphen = chr(45);// "-" $uuid = substr($charid, 0, 8).$hyphen .substr($charid, 8, 4).$hyphen .substr($charid,12, 4).$hyphen .substr($charid,16, 4).$hyphen .substr($charid,20,12); return $uuid; }
第二步。关于这个byte数组让人很困惑,莫非要转成byte数组?但是在使用mcrypt加密的时候发现要求传入字符串,后来食药监局的技术人员耐心讲解道:加密的底层实现都是utf8的byte数组。所以只要传utf8的字符串就可以了,至于byte数组,应该是mcrypt内部实现的,不用管了。生成初始化向量和密匙的第三条里的填充用pcks7方式填充。关于pcks7填充,是怎么个填充,看代码,一目了然。
function pkcs7padding($source){ $source = trim($source); $block = mcrypt_get_block_size(‘rijndael-128‘, ‘cbc‘); $pad = $block - (strlen($source) % $block); if ($pad <= $block) { $char = chr($pad); $source .= str_repeat($char, $pad); } return $source; }
到这里似乎该加密了。带着激动的心情发过去,不出意料的,不对。原来,这里所谓pcks7填充模式,不仅是填充初始化向量和密匙,加密的明文也要填充滴。
下面是整体的代码:
class AesCrypterClass { const URL="http://spzf.smda.gov.cn/"; static $companyInfo = array(‘id‘=>‘xx‘, ‘name‘=>‘xx‘, ‘website‘=>‘www.xx.cn‘, ‘password‘=>‘xx‘ ); private $algorithm; private $mode; public function __construct($algorithm = MCRYPT_RIJNDAEL_128,$mode = MCRYPT_MODE_CBC) { $this->algorithm = $algorithm; $this->mode = $mode; } /** *生成validate验证字符串 *AES加密,加密模式:CBC;填充模式:PKCS7。 * @since 2015-11-16 * @param array $orig_data 参数说明 * string id 第三方标识 * string name 第三方名称 * string password 密码 * string website 第三方网站地址 * @return string */ public function createValidate() { $orig_data = self::$companyInfo; $iv = $this->getIvParameter(array(‘id‘=>$orig_data[‘id‘],‘name‘=>$orig_data[‘name‘])); $key = $this->getKey(array(‘password‘=>$orig_data[‘password‘],‘website‘=>$orig_data[‘website‘])); $guid = $this->createGuid(); $data = array(‘id‘=>$orig_data[‘id‘], ‘name‘=>$orig_data[‘name‘], ‘website‘=>$orig_data[‘website‘], ‘gkey‘=>$guid ); $jsonData = json_encode($data, JSON_UNESCAPED_UNICODE); $jsonData = $this->pkcs7padding($jsonData); $encrypted = mcrypt_encrypt($this->algorithm, $key, $jsonData, $this->mode, $iv); $encryptText = urlencode(base64_encode($encrypted)); return $encryptText; } /** *pkcs7填充 * @since 2015-11-16 */ function pkcs7padding($source){ $source = trim($source); $block = mcrypt_get_block_size(‘rijndael-128‘, ‘cbc‘); $pad = $block - (strlen($source) % $block); if ($pad <= $block) { $char = chr($pad); $source .= str_repeat($char, $pad); } return $source; } /** *字符串转换为utf8编码方式 * @since 2015-11-16 */ public function utf8str($str) { $encode = mb_detect_encoding( $str, array(‘ASCII‘,‘UTF-8‘,‘GB2312‘,‘GBK‘)); if ( $encode !=‘UTF-8‘ ){ $str = iconv($encode,‘UTF-8‘,$str); } return $str; } /** *生成初始化向量IV * @since 2015-11-16 * @param array $args 参数说明 * string id 第三方标识 * string name 第三方名称 * @return string */ public function getIvParameter($args){ $str = $args[‘id‘].$args[‘name‘]; $utf8str = $this->utf8str($str); if(strlen($utf8str)<16){ $iv = $this->pkcs7padding($utf8str, 16); }else{ $iv = substr($utf8str, 0, 16); } return $iv; } /** *生成密匙 * @since 2015-11-16 * @param array $args 参数说明 * string password 密码 * string website 第三方网站地址 * @return string */ public function getKey($args){ $str = $args[‘password‘].$args[‘website‘].date(‘Ymd‘); $utf8str = $this->utf8str($str); if(strlen($utf8str)<32){ $key = $this->pkcs7padding($utf8str, 32); }else{ $key = substr($utf8str, 0, 32); } return $key; } /** *生成随机数GUID * @since 2015-11-16 */ public function createGuid() { $charid = md5(uniqid(mt_rand(), true)); $hyphen = chr(45);// "-" $uuid = substr($charid, 0, 8).$hyphen .substr($charid, 8, 4).$hyphen .substr($charid,12, 4).$hyphen .substr($charid,16, 4).$hyphen .substr($charid,20,12); return $uuid; } /** *获取Token * @since 2015-11-16 * @param array $args 参数说明 * string id 第三方标识 * string validate 验证字符串 * @return string */ public function getToken($args){ $url = self::URL.‘api/user/authenticate? id=‘.$args[‘id‘].‘&validate=‘.$args[‘validate‘]; $ch = curl_init (); curl_setopt ( $ch, CURLOPT_URL, $url); curl_setopt ( $ch, CURLOPT_HEADER, 0 ); curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, 1 ); $return = curl_exec ( $ch ); $httpCode= curl_getinfo($ch,CURLINFO_HTTP_CODE); //403错误可能由于8小时内重新拉取token导致,加reCheck参数重新获取 if($httpCode==‘403‘){ $url = $url.‘&reCheck=1‘; curl_setopt ( $ch, CURLOPT_URL, $url); $return = curl_exec ( $ch ); $httpCode= curl_getinfo($ch,CURLINFO_HTTP_CODE); } curl_close ( $ch ); return array(‘httpCode‘=>$httpCode,‘token‘=>$return); } /** *获取餐厅分级信息 * @since 2015-11-16 * @param array $args 参数说明 * string id 餐厅许可证号 * string token 验证token * @return array * License string 许可证号 * OrgName string 单位名称 * CheckDate date 检查日期 * CheckResult string 检查结果,为良好、一般、较差 * Signage string 店招,会有无效或无意义的值,仅供参考 * Address string 地址 */ public function getRestaurantGradeInfo($args){ $url = self::URL.‘api/supervise/‘.$args[‘id‘]; $headerArr = array("HOST:{$args[‘host‘]}","Authorization:FY {$args[‘token‘]}"); $ch = curl_init (); curl_setopt ( $ch, CURLOPT_URL, $url); curl_setopt ( $ch, CURLOPT_HEADER, 0 ); curl_setopt ( $ch, CURLOPT_HTTPHEADER, $headerArr); curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, 1 ); $return = curl_exec ( $ch ); $httpCode = curl_getinfo($ch,CURLINFO_HTTP_CODE); curl_close ( $ch ); return array(‘httpCode‘=>$httpCode,‘gradeItem‘=>$return); } }
标签:
原文地址:http://www.cnblogs.com/tomorrowdemo/p/5001312.html