api接口数据-验证-整理

在Thinkphp官网发布 发布日期: 2019/10/18
但是不知道为什么,有时候,我好不容易写了一篇文章要发布,发送成功了,
但是在文章中心就是看不到,所以决定将部分文章转移至csdn
主要是为了方便自己查看
整理一下,前端向接口请求数据时的验证:比如我写了一个文章列表数据接口,那么我需要验证哪些规则,由此,我想了一下,除开签名验证,大概就只有ssl协议,白名单[ip,域名,url],黑名单[ip,域名,url],请求频率[eg:每10秒,最大请求数],设备【电脑,手机】,终端浏览器[微信,qq,…],设置请求方式并禁用curl获取数据[保证用户只能在页面使用ajax请求]。
如果不做请求方式的限制,那么就其他人就能通过curl方式获取到数据,于是写了下面一个例子

<?php
/**
 *  +----------------------------------------------------------------------
 *  | ThinkPHP [ WE CAN DO IT JUST THINK ]
 *  +----------------------------------------------------------------------
 *  | Copyright (c) 2019 ahai574 All rights reserved.
 *  +----------------------------------------------------------------------
 *  | Licensed ( ++++ahai574++++ )
 *  +----------------------------------------------------------------------
 *  | Author: 阿海 <764882431@qq.com>
 *  +----------------------------------------------------------------------
 */
/**
 * 请求验证
 * demo:
 * $checkRequest = new CheckRequest();
 *      $checkRequest->setAjax('get',true);
 *      $checkRequest->setBlackList('10.0.0.155',false);
 *      $checkRequest->setWhiteList('10.0.0.15');
 *      $checkRequest->setDevice('mobile,pc',false);
 *      $checkRequest->setTerminal('uc,weixin',false);
 *      $checkRequest->setFrequent(10,3,true);
 *      $checkRequest->setSsl(false);
 *      $result = $checkRequest->check();
 * if(!$result['result']) return json($result);
 */
namespace app\common\library;
use think\Controller;
use think\Exception;
use think\facade\Request;
class CheckRequest extends Controller
{
    /**
     * 开启 协议请求 必须是 https
     * boolean
     */
    private $isSsl = false;
    /**
     * 开启 验证请求 为 【页面内】ajax请求
     * boolean
     */
    private $isAjax = true;
    /**
     * ajax请求方式[eg:[post,get,put]]
     * array
     */
    private $ajax = [];
    /**
     * 是否开启 频繁请求验证
     * boolean
     */
    private $isFrequently = false;
    /**
     * 频繁请求 的 秒数
     * int
     */
    private $requestTime = 10;
    /**
     * 频繁请求 ($requestTime)10秒 内 的 最大访问次数
     * int
     */
    private $frequency = 50;
    /**
     * 是否开启白名单验证
     * boolean
     */
    private $isWhiteList = false;
    
    /**
     * ip白名单 或者 域名白名单
     * [
     * 完整的域名(eg:http:test.baidu.com),主域名(eg:baidu.com),
     * 子域名[eg:test.baidu.com],url完整路径(eg:http://test.baidu.com/test/test.html)
     * ]
     * array
     */
    private $whiteList = ['127.0.0.1'];
    /**
     * 是否开启黑名单验证  【优先级大于白名单】
     * boolean
     */
    private $isBlackList = false;
    
    /**
     * ip黑名单 或者 域名黑名单
     * [
     * 完整的域名(eg:http:test.baidu.com),主域名(eg:baidu.com),
     * 子域名[eg:test.baidu.com],url完整路径(eg:http://test.baidu.com/test/test.html)
     * ]
     * array
     */
    private $blackList = [];
    /**
     * 是否开启设备验证
     * boolean
     */
    private $isDevice = false;
    /**
     * 设备类型 手机[mobile] 电脑['pc'] 
     * array
     */
    private $device = ['mobile'];
    /**
     * 是否开启终端验证
     * boolean
     */
    private $isTerminal = false;
    /**
     * 终端浏览器类型 (eg:['weixin','qq','baidu','uc'])
     * array
     */
    private $terminal = ['weixin'];
     /**
     * 构造函数 constructor.
     */
    public function __construct($config = [])
    {
        parent::__construct();
        if(isset($config) && !is_array($config)){
            throw new Exception("构造参数config必须是数组");  
        }
        $this->isSsl = isset($config['isSsl']) && !empty($config['isSsl']) ? $config['isSsl'] : $this->isSsl;
        $this->isAjax = isset($config['isAjax']) && !empty($config['isAjax']) ? $config['isAjax'] : $this->isAjax;
        $this->ajax = isset($config['ajax']) && is_array($config['ajax']) ? $config['ajax'] : $this->ajax;
        $this->isFrequently = isset($config['isFrequently']) && !empty($config['isFrequently']) ? $config['isFrequently'] : $this->isFrequently;
        $this->requestTime = isset($config['requestTime']) && !empty($config['requestTime']) ? $config['requestTime'] : $this->requestTime;
        $this->frequency = isset($config['frequency']) && !empty($config['frequency']) ? $config['frequency'] : $this->frequency;
        $this->isWhiteList = isset($config['isWhiteList']) && !empty($config['isWhiteList']) ? $config['isWhiteList'] : $this->isWhiteList;  
        $this->whiteList = isset($config['whiteList']) && is_array($config['whiteList']) ? array_merge($this->whiteList, $config['whiteList']) : $this->whiteList;
        $this->isBlackList = isset($config['isBlackList']) && !empty($config['isBlackList']) ? $config['isBlackList'] : $this->isBlackList;  
        $this->blackList = isset($config['blackList']) && is_array($config['blackList']) ? array_merge($this->blackList, $config['blackList']) : $this->blackList;
        $this->isDevice = isset($config['isDevice']) && !empty($config['isDevice']) ? $config['isDevice'] : $this->isDevice;
        $this->device = isset($config['device']) && is_array($config['device']) ? $config['device'] : $this->device;
        $this->isTerminal = isset($config['isTerminal']) && is_array($config['isTerminal']) ? $config['isTerminal'] : $this->isTerminal;
        $this->terminal = isset($config['terminal']) && is_array($config['terminal']) ? $config['terminal'] : $this->terminal;
    
    }
 
    /**
     * 检测请求行为
     * @return boolean
     */
    public function check()
    {
        //验证黑名单--
        if($this->isBlackList){
            //ip,主域名,包含协议域名,请求的url完整路径, 主域名
            $requestList = [Request::ip(),Request::host(),Request::domain(),Request::url(true),Request::rootDomain()];
        
            if(!empty(array_intersect($this->blackList, $requestList)) ){
                return ['result'=>false, 'errorMsg'=>'域名[ip]已被禁用', 'code'=>200];
            }else{
                //读取数据库黑名单表
                $list = db('request_blacklist')
                ->whereOr('ip','eq',Request::ip())
                ->whereOr('domain','eq',Request::domain())
                ->whereOr('domain','eq',Request::host())
                ->whereOr('domain','eq',Request::rootDomain())
                ->whereOr('domain','eq',Request::url(true))
                ->find();
                if(!is_null($list)){
                    return ['result'=>false, 'errorMsg'=>'域名[ip]已被禁用', 'code'=>200];
                }
            }
            
        }
        //验证ssl协议
        if($this->isSsl){
            if(!Request::isSsl()){
                return ['result'=>false, 'errorMsg'=>'请求协议必须是https协议', 'code'=>200];
            }
        }
     
        //验证是否ajax 必须是页面内的请求  [避开curl请求,浏览器直接输入地址]
       if($this->isAjax){
           if(empty($this->ajax)){
                if(!Request::isAjax()){
                    return ['result'=>false, 'errorMsg'=>'非法请求', 'code'=>200];
                }
           }else{
                if(!in_array(Request::method(), $this->ajax))
                {
                    return ['result'=>false, 'errorMsg'=>'非法请求', 'code'=>200];
                }
           }  
       }
       //验证请求频率
       if($this->isFrequently){
            $data = [
                'method'            =>  Request::method(),
                'param'             =>  json_encode(Request::param()),
                'ip'                =>  Request::ip(),
                'url'               =>  Request::url(true),
                'http_user_agent'   =>  $_SERVER['HTTP_USER_AGENT'],
                'is_mobile'         =>  Request::isMobile()?1:0,
                'create_time'       =>  time()
            ];
            db('request_log')->insert($data);
            $where = [
                ['ip','=',Request::ip()],
                ['create_time',">=",time()-$this->requestTime]
            ];
            $list = db('request_log')->where($where)->count('id');
            if($list > $this->frequency){
                $data = [
                    'ip'            =>  Request::ip(),
                    'domain'        =>  Request::domain(),
                    'content'       =>  '频繁请求',
                    'create_time'   =>  time()
                ];
                db('request_blacklist')->insert($data);
                return ['result'=>false, 'errorMsg'=>'请求过于频繁,请稍后再进行请求', 'code'=>200];
            }
       }
       //验证ip域名白名单
       if($this->isWhiteList){
           //ip,主域名,包含协议域名,请求的url完整路径, 主域名
            $requestList = [Request::ip(),Request::host(),Request::domain(),Request::url(true),Request::rootDomain()];
            if( empty(array_intersect($this->whiteList, $requestList)) ){           
                 //读取数据库黑名单表
                 $list = db('request_whitelist')
                 ->whereOr('ip','eq',Request::ip())
                 ->whereOr('domain','eq',Request::domain())
                 ->whereOr('domain','eq',Request::host())
                 ->whereOr('domain','eq',Request::rootDomain())
                 ->whereOr('domain','eq',Request::url(true))
                 ->find();
                 if(is_null($list)){
                     return ['result'=>false, 'errorMsg'=>'域名[ip]不在白名单中', 'code'=>200];
                 } 
            }
        }
       //验证设备类型
       if($this->isDevice){
            $requestDevice = Request::isMobile() ? 'mobile' : 'pc';
            if( !in_array($requestDevice, $this->device) ){
                return ['result'=>false, 'errorMsg'=>'不支持当前设备', 'code'=>200];
            }
       }
       //验证终端--
       if($this->isTerminal){
            $requestTerminal = $this->getBrowser();
            if( !in_array($requestTerminal, $this->terminal) ){
                return ['result'=>false, 'errorMsg'=>'不支持当前浏览器', 'code'=>200];
            }
       }
       return ['result'=>true, 'msg'=>'请求通过', 'code'=>200];
    }
   /**
     * 设置 ip 域名 白名单
     * @param $blackList array
     * @param $isBlackList boolean
     */
    public function setBlackList($blackList = [], $isBlackList = true)
    {
        if(!is_array($blackList))
        {
            $blackList = explode(",", $blackList);
        }
        if(!is_bool($isBlackList))
        {
            throw new Exception("参数isBlackList必须是boolean");  
        }
        
        $this->blackList = array_merge($this->blackList, $blackList);
        $this->isBlackList = $isBlackList;
        return $this;
    } 
    /**
     * 判断是否微信浏览器
     */
    private function getBrowser()
    {
       $agent   = $_SERVER['HTTP_USER_AGENT'];
        if(strpos($agent, 'MicroMessenger') !== false)
        {
            return "weixin";
        } else if(strpos($agent, 'QQBrowser') !== false)
        {
            return "qq";
        } else if(strpos($_SERVER['HTTP_USER_AGENT'],'UCBrowser')!==false||strpos($_SERVER['HTTP_USER_AGENT'],'UCWEB')!==false)
        {
            return "uc";
        } else if(strpos($agent, 'baidu') !== false)
        {
            return "baidu";
        }else
        {
            return "other";
        }
    }
    /**
     * 设置是否开启 ajax请求验证
     * @param $ajax array [post,get] 
     * @param $isAjax boolean
     */
    public function setAjax( $ajax = [] ,$isAjax = true )
    {
        if(!is_array($ajax)){
            $ajax = explode(",", $ajax);
        }
    
        if(!is_bool($isAjax)){
            throw new Exception("参数isAjax必须是boolean类型");  
        }
        $this->ajax = array_map('strtoupper',$ajax);
        $this->isAjax = $isAjax;
        return $this;
    }
    /**
     * 设置是否开启 协议验证
     * @param $isSsl boolean
     */
    public function setSsl( $isSsl = true )
    {
        if(!is_bool($isSsl)){
            throw new Exception("参数isSsl必须是boolean类型");  
        }
        $this->isSsl = $isSsl;
        return $this;
    }
    /**
     * 设置 频繁请求的参数
     * @param $isFrequently 是否开启验证 
     * @param $requestTime 设置验证的时间数
     * @param $frequently 设置在规定的时间内的最大请求数
     */
    public function setFrequent($requestTime = 10, $frequency = 50, $isFrequently = true )
    {
        if(!is_int($requestTime)||!is_int($frequency)){
            throw new Exception("参数[requestTime,requestTime]必须是integer类型");  
        }
        if(!is_bool($isFrequently)){
            throw new Exception("参数frequently必须是boolean类型");  
        }
        $this->requestTime = $requestTime;
        $this->frequency = $frequency;
        $this->isFrequently = $isFrequently;
        return $this;
    }
    /**
     * 设置 ip 域名 白名单
     * @param $whiteList array
     * @param $isWhiteList boolean
     */
    public function setWhiteList($whiteList = [], $isWhiteList = true)
    {
        if(!is_array($whiteList))
        {
           $whiteList = explode(",", $whiteList);
        }
        if(!is_bool($isWhiteList))
        {
            throw new Exception("参数isWhiteList必须是boolean");  
        }
        
        $this->whiteList = array_merge($this->whiteList, $whiteList);
        $this->isWhiteList = $isWhiteList;
        return $this;
    } 
    /**
     * 设置 设备类型
     * @param $device array | string 
     * @param $isDevice 是否开启验证
     */
    public function setDevice($device = [], $isDevice = true)
    {
        if(!is_array($device))
        {
            $device = explode(",", $device);
        } 
        if(!is_bool($isDevice))
        {
            throw new Exception("参数isDevice必须是boolean");  
        }
        $this->device = $device;
        $this->isDevice = $isDevice;
        return $this;
    } 
    /**
     * 设置 设备类型
     * @param $terminal array | string 
     * @param $isTerminal 是否开启验证
     */
    public function setTerminal($terminal = [], $isTerminal = true)
    {
        
        if(!is_array($terminal))
        {
            $terminal = explode(",", $terminal);
        } 
        if(!is_bool($isTerminal))
        {
            throw new Exception("参数isTerminal必须是boolean");  
        }
        $this->terminal = $terminal;
        $this->isTerminal = $isTerminal;
        return $this;
    } 
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值