thinkphp6: 给接口api做签名验证(php 8.1.1 / thinkphp v6.0.10LTS )
作者:互联网
一,创建middelware和controller
liuhongdi@lhdpc:/data/php/admapi$ php think make:middleware CheckSign Middleware:app\middleware\CheckSign created successfully.
liuhongdi@lhdpc:/data/php/admapi$ php think make:controller Pay Controller:app\controller\Pay created successfully.
说明:刘宏缔的架构森林是一个专注架构的博客,地址:https://www.cnblogs.com/architectforest
对应的源码可以访问这里获取: https://github.com/liuhongdi/
或: https://gitee.com/liuhongdi
说明:作者:刘宏缔 邮箱: 371125307@qq.com
二,编写php代码:
1,middleware/CheckSign.php<?php declare (strict_types = 1); namespace app\middleware; use app\result\Result; use app\lib\util\sign; class CheckSign { //第三方对接口的访问不需要检查 private $notCheck = ["/pay/alipayreturn","/pay/alipayrotify"]; /** * 处理请求 * * @param \think\Request $request * @param \Closure $next * @return Response */ public function handle($request, \Closure $next) { $uri = $request->server("REQUEST_URI"); //如果是不需检查的uri if (in_array($uri ,$this->notCheck)) { return $next($request); } else { $sign = new sign(); $param = $request->request(); unset($param['s']); //检查参数的sign $res = $sign->verifySign($param); if ($res['code'] == 0){ return $next($request); } else { return Result::Error(1,$res['msg']); } } } }2,lib/util/sign.php
<?php namespace app\lib\util; class sign { private $appId = "lc20220118"; private $appKey = "u665698fzur5e2t85tyu142"; //创建sign public function makeSign($data) { ksort($data); $string = $this->toUrlParams($data); $string = $string . "&key=" . $this->appKey; $string = md5($string); $result = strtolower($string); return $result; } //检验sign是否正确 public function verifySign($data) { //check sign if (!isset($data['sign']) || !$data['sign']) { return ['code'=>1,'msg'=>'发送的数据签名不存在']; } //check sign if (!isset($data['appid']) || !$data['appid']) { return ['code'=>1,'msg'=>'发送的应用参数1不存在']; } if ($data['appid'] != $this->appId) { return ['code'=>1,'msg'=>'发送的应用参数1错误']; } //check sign if (!isset($data['nonce']) || !$data['nonce']) { return ['code'=>1,'msg'=>'发送的应用参数2不存在']; } //check timestamp if (!isset($data['timestamp']) || !$data['timestamp']) { return ['code'=>1,'msg'=>'发送的数据参数不合法']; } // 验证请求, 10分钟失效 if (time() - $data['timestamp'] > 600) { return ['code'=>1,'msg'=>'验证超时, 请重新发送请求']; } $clientSign = $data['sign']; unset($data['sign']); $serverSign = $this->makeSign($data); if ($clientSign == $serverSign) { return ['code'=>0,'msg'=>'验证通过']; } else { return ['code'=>1,'msg'=>'请求不合法']; } } //生成url字符串 private function toUrlParams($values){ $buff = ""; foreach ($values as $k => $v) { //&& $v != "" if($k != "sign" && !is_array($v)){ $buff .= $k . "=" . $v . "&"; } } $buff = trim($buff, "&"); return $buff; } }3,controller/Pay.php
<?php declare (strict_types = 1); namespace app\controller; use think\Request; class Pay { /** * return * * @return \think\Response */ public function alipayReturn() { echo "alipayReturn"; exit; } /** * notify * * @return \think\Response */ public function alipayNotify() { echo "alipayNotify"; exit; } }
三,编写vue代码:
说明:vue代码仅供演示,因为js中无法安全保存appkey, 所以web/wap等不需要做验证:<template> <div style="text-align: left;"> id:{{article.id}}<br/> title:{{article.title}}<br/> content:{{article.content}}<br/> </div> </template> <script> import {apiArticleOne} from "../api/api"; import {ElMessage} from "element-plus"; import {ref} from "vue"; import md5 from 'js-md5'; export default { name: "Article", setup() { const article = ref([]); //得到sign const getSign = (param,key) => { let str = ""; for(var idx in param) { let one = idx+"="+param[idx]; if (str == "") { str = one; } else { str = str+"&"+one; } } str = str+"&key="+key; //console.log("before md5:"+str); let md5str = md5(str); return md5str; } //得到参数对象 const getParam = (id) => { let appid = "lc20220118"; let appkey = "u665698fzur5e2t85tyu1421"; let timestamp = parseInt((new Date()).getTime()/1000); let nonce = Math.floor(Math.random()*8999)+1000; let param = { appid:appid, id:id, nonce:nonce, timestamp:timestamp, } let sign = getSign(param,appkey); param.sign = sign; return param; } //查询得到一篇文章的内容: const getArticle = () => { var param = getParam(1); apiArticleOne(param).then(res => { //成功 if (res.code == 0) { article.value = res.data; } else { ElMessage.error("获取表单令牌失败:"+res.msg); } }).catch((error) => { console.log(error) }) } getArticle(); return { article, } } } </script> <style scoped> </style>
四,测试效果:
1,成功返回数据时: 2,appkey不正确时: 3,直接访问接口时报错: 4,访问不做check的接口:五,查看php和thinkphp的版本:
php:liuhongdi@lhdpc:/data/php/admapi$ php --version PHP 8.1.1 (cli) (built: Dec 20 2021 16:12:16) (NTS) Copyright (c) The PHP Group Zend Engine v4.1.1, Copyright (c) Zend Technologies with Zend OPcache v8.1.1, Copyright (c), by Zend Technologiesthinkphp:
liuhongdi@lhdpc:/var/www/html$ cd /data/php/admapi/ liuhongdi@lhdpc:/data/php/admapi$ php think version v6.0.10LTS
标签:8.1,v6.0,code,return,10LTS,param,sign,php,data 来源: https://www.cnblogs.com/architectforest/p/15832850.html