ThinkPHP6利用前端跨域请求限制实现域名授权

前言

晓杰最近在开发一个活码引流系统,功能基本已经开发完成,正在研究授权方面的问题,下面是晓杰研究出来的结果,分享给大家,不喜勿喷!

研究过程

由于前后端分离架构,前端使用了Vue2.6 后端使用了ThinkPHP6 ,刚开始开发的时候就遇到了跨域请求失败的问题。

后续将后台增加了 $header[‘Access-Control-Allow-Origin’] = * 才解决了跨域问题,到了授权问题晓杰就想着是否可以利用该机制进行授权认证,目前晓杰暂时使用该授权方案。

创建授权表

新增授权站点

    public static function add($param){
        try {
           $validate = new AppConfigValidate();
            if (!$validate->scene('beforAdd')->check($param)) {
                return Res::error($validate->getError());
            }
            $param['status']=1;
            if(!$validate->scene('add')->check($param)){
                return  Res::error($validate->getError());
            }
           AppConfigModel::add($param);
            LogService::write('添加','添加');
          return  Res::ok();
        }catch (\PDOException $e){
            return Res::error($e->getMessage());
        }
    }

正常的新增,在支付授权订单后进行回调

//利用订单回调字符串 修改站点授权状态
$param = [
   'id' => $order['order_str'],
   'status' =>2
   ];
if (!AppConfigModel::edit($param)) {
   return 'fail';
}
//修改成功后 查询授权站点域名
$appInfo = AppConfigModel::findById($order['order_str']);
$redis = new Redis();
//加入Redis 后面会讲到这个作用
$redisKey = "newSoft:whiteHost:".$appInfo['app_domain'];
$redis ->set($redisKey,1);

授权检测

晓杰刚开始直接用查询数据库方式进行授权检测,但是考虑因为这个授权检测每次请求都会进行查询数据库,并发多了对服务器压力会变成负担,所以就想了个方案,Redis,刚开始还用array存储白名单 然后再进行in_array 判断,晓杰觉得还是繁琐,一不做二不休 直接利用RedisKey是否存在进行判断。下面是实现代码,如有不足之处希望大家指出。

<?php

namespace app\common\middleware;


use app\common\utils\Massage;
use app\common\utils\Res;
use app\group\appConfig\model\AppConfigModel;
use Closure;
use think\cache\driver\Redis;
use think\Config;

class AllowCrossDomain
{

    protected $cookieDomain;

    protected $header = [
        'Access-Control-Allow-Credentials' => 'true',
        'Access-Control-Max-Age'           => 1800,
        'Access-Control-Allow-Methods'     => 'GET, POST, PATCH, PUT, DELETE, OPTIONS',
        'Access-Control-Allow-Headers'     => 'Authorization, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, X-CSRF-TOKEN, X-Requested-With,token',
    ];

    public function __construct(Config $config)
    {
        $this->cookieDomain = $config->get('cookie.domain', '');
    }
    //校验白名单
    private static function checkWhiteHost($host){
        $redis = new Redis();
        $redisKey = "newSoft:whiteHost:localhost";
        //先判断localhost是否存在 不存在说明没有进行初始化
        if (empty($redis ->get($redisKey))){
            $map[] = ['status', '=', 2];
            $whiteHostList = AppConfigModel::list($map);
            $redis = new Redis();
            foreach ($whiteHostList as $key => $value){
                $redisKey = "newSoft:whiteHost:".$value['app_domain'];
                $redis ->set($redisKey,1);
            }
            $redisKey = "newSoft:whiteHost:localhost";
            $redis ->set($redisKey,1);
            $redisKey = "newSoft:whiteHost:127.0.0.1";
            $redis ->set($redisKey,1);
        }
        //组装RedisKey
        $redisKey = "newSoft:whiteHost:".$host;
        if (empty($redis ->get($redisKey))){
        //不存在返回false
            return false;
        }
        return true;
    }
    public function handle($request, Closure $next, ?array $header = [])
    {
        $header = !empty($header) ? array_merge($this->header, $header) : $this->header;

        if (!isset($header['Access-Control-Allow-Origin'])) {
            $origin = $request->header('origin');
            //获取请求host
            $host = parse_url($origin)['host'];
            //校验白名单
            if (!self::checkWhiteHost($host)){
            	//失败返回站点未授权
                return Res::error(Massage::WEBSITE_ERROR);
                die();
            }
            $header['Access-Control-Allow-Origin'] = $origin;
         
        }

        return $next($request)->header($header);
    }

}

#效果
刚测试没增加127.0.0.1这个域名白名单


增加进白名单后请求成功

本文作者

Soujer