利用yii2实现项目授权认证

1.准备一个基本参数的文本,这里为licence.info

{
    "permittedFor": "00:0c:29:f0:03:4d",    //颁发单位,这里为机器mac地址
    "expiredAt":"",    //过期时间
    "pptLimit":0,    //购买的PPT识别服务的使用次数(这里具体情况而定,业务不同)
	"voiceLimit":0,  //购买的同声传译识别服务的使用次数(这里具体情况而定,业务不同)
	"issuedAt":"2020/2/18 12:00:00",    //颁发时间
	"issuedBy":"xxxx.com"    //颁发单位
}

注释:这里为具体用户的购买情况的文本,我们记录下来,因为会根据参数来生成对应的密钥key。

2.准备一个空文件key.lic用来存放密钥

3.准备一个空文件licence.lic来存方加密的文本信息

如图:

4.在console下新建控制器ReduceController继承自\yii\console\Controller

public function actionEncrypt()
	{
//		$data = [
//			'permittedFor' => \Yii::$app->helper->getMAC(),//颁发给的机器mac,可以数组或字符串
//			'expiredAt' => date('Y-m-d H:i:s'),//过期时间
//			'pptLimit' => 30,//ppt任务数限制
//			'voiceLimit' => 20,//同声传译任务数限制
//			'issuedAt' => date('Y-m-d H:i:s'),//颁发时间
//			'issuedBy' => 'xxxx.cn',//颁发单位
//			'id'=>\Yii::$app->getSecurity()->generateRandomString()
//		];
		$licenceDir = ArrayHelper::getValue(Yii::$app->params, 'licenceFiles');
		if (empty($licenceDir)) {
			$licenceDir = '.';
		}
		$keyFile = $licenceDir . DIRECTORY_SEPARATOR . 'key.lic';
		$licenceFile = $licenceDir . DIRECTORY_SEPARATOR . 'licence.lic';
		$registerFile = $licenceDir . DIRECTORY_SEPARATOR . 'licence.info';
		$encryptString = file_get_contents($registerFile);
		$encryptData = json_decode($encryptString, true);
		$encryptData['id'] = Yii::$app->getSecurity()->generateRandomString();
		$encryptString = json_encode($encryptData);
		$key = md5($encryptString);
		$encrypt = Yii::$app->getSecurity()->encryptByKey($encryptString, $key);
		file_put_contents($licenceFile, $encrypt);
		file_put_contents($keyFile, $key);
		$this->stdout('done');
		$this->stdout(PHP_EOL);
		return ExitCode::OK;
	}
建立好后我们需要启动命令,生成一个licence.lic和key.lic文件,这是加密后的密文和解密的密钥

下面开始解密授权:

<?php

namespace common\components;

use yii\base\BaseObject;
use yii\helpers\ArrayHelper;

class Licence extends BaseObject
{
	private $licenceFile;
	private $keyFile;
	private $registerFile;
	private $key;
	private $licence;
	private $macAddresses;
	private $taskCount = [];

	public function init()
	{
		parent::init(); // TODO: Change the autogenerated stub
		$licenceDir = ArrayHelper::getValue(\Yii::$app->params, 'licenceFiles');
		if (empty($licenceDir)) {
			$licenceDir = '../..';
		}
		$this->keyFile = $licenceDir . DIRECTORY_SEPARATOR . 'key.lic';
		$this->licenceFile = $licenceDir . DIRECTORY_SEPARATOR . 'licence.lic';
		$this->registerFile = \Yii::getAlias('@common') . DIRECTORY_SEPARATOR . 'register.info';
		if (!file_exists($this->keyFile)) {
			throw new \Exception('授权文件缺失');
		}
		if (!file_exists($this->licenceFile)) {
			throw new \Exception('授权文件缺失');
		}
		$key = file_get_contents($this->keyFile);
		$licence = file_get_contents($this->licenceFile);
		$encryptedString = \Yii::$app->getSecurity()->decryptByKey($licence, $key);
		if (empty($encryptedString)) {
			throw new \Exception('授权licence无效');
		}
		$licenceData = json_decode($encryptedString, true);
		if (empty($licenceData)) {
			throw new \Exception('授权licence无效');
		}
		if (empty($licenceData['id'])) {
			throw new \Exception('授权licence格式无效');
		}
		if (empty($licenceData['issuedAt'])) {
			throw new \Exception('授权licence格式无效');
		}
		if (!isset($licenceData['expiredAt'])) {
			throw new \Exception('授权licence格式无效');
		}
		if (!isset($licenceData['permittedFor'])) {
			throw new \Exception('授权licence格式无效');
		}
		if (!isset($licenceData['pptLimit'])) {
			throw new \Exception('授权licence格式无效');
		}
		if (!isset($licenceData['voiceLimit'])) {
			throw new \Exception('授权licence格式无效');
		}
		$issuedAt = strtotime(ArrayHelper::getValue($licenceData, 'issuedAt'));
		$now = time();
		if ($now < $issuedAt) {
			throw new \Exception('licence生成时间错误,授权验证失败');
		}
		$expiredAt = ArrayHelper::getValue($licenceData, 'expiredAt');
		if (!empty($expiredAt)) {
			$expiredAtTime = strtotime($expiredAt);
			if ($now >= $expiredAtTime) {
				throw new \Exception('授权licence已过期,授权验证失败');
			}
		}
		$permittedFor = ArrayHelper::getValue($licenceData, 'permittedFor');
		if (!empty($permittedFor)) {
			$macAddress = $this->getMAC();
			if (empty($macAddress)) {
				throw new \Exception('无法获取服务器mac地址,授权验证失败');
			}
			$this->macAddresses = $macAddress;
			if (is_array($permittedFor)) {
				$intersect = array_intersect($permittedFor, $macAddress);
				if (empty($intersect)) {
					throw new \Exception('服务器mac地址不匹配,授权验证失败');
				}
			} else {
				if (!in_array($permittedFor, $macAddress)) {
					throw new \Exception('服务器mac地址不匹配,授权验证失败');
				}
			}
		}
		$this->licence = $licenceData;
		$this->key = $key;
	}

	private function getMAC()
	{
		$return_array = [];
		switch (strtolower(PHP_OS)) {
			case "linux":
				$return_array = $this->forLinux();
				break;
			case "unix":
			case "aix":
			case "solaris":
				break;
			default:
				$return_array = $this->forWindows();
				break;
		}
		$mac_addr = [];
		$temp_array = array();
		foreach ($return_array as $value) {
			if (preg_match("/[0-9a-f][0-9a-f][:-]" . "[0-9a-f][0-9a-f][:-]" . "[0-9a-f][0-9a-f][:-]" . "[0-9a-f][0-9a-f][:-]" . "[0-9a-f][0-9a-f][:-]" . "[0-9a-f][0-9a-f]/i", $value, $temp_array)) {
				$mac_addr[] = $temp_array[0];
			}
		}
		unset($temp_array);
		return $mac_addr;
	}

	private function forWindows()
	{
		if (!function_exists('exec')) {
			throw new \Exception('exec方法不可用,无法获取服务器mac地址');
		}
		@exec("ipconfig /all", $return_array);
		if ($return_array)
			return $return_array;
		else {
			$ipconfig = $_SERVER["WINDIR"] . "system32ipconfig.exe";
			if (is_file($ipconfig))
				@exec($ipconfig . " /all", $return_array);
			else
				@exec($_SERVER["WINDIR"] . "systemipconfig.exe /all", $return_array);
			return $return_array;
		}
	}

	private function forLinux()
	{
		if (!function_exists('exec')) {
			throw new \Exception('exec方法不可用,无法获取服务器mac地址');
		}
		@exec('ifconfig -a', $output, $returnArray);
		if ($returnArray === 0) {
			return $output;
		}
		@exec("/usr/sbin/ifconfig -a", $output, $returnArray);
		if ($returnArray === 0) {
			return $output;
		}
		throw new \Exception('无法获取服务器mac地址,exec状态码:' . $returnArray);
	}


	/**
	 * @return mixed
	 * @throws \Exception
	 */
	public function getMacAddress()
	{
		if (empty($this->macAddresses)) {
			$this->macAddresses = $this->getMAC();
			if (empty($this->macAddresses)) {
				throw new \Exception('获取服务器mac地址失败');
			}
		}
		$macAddress = reset($this->macAddresses);;
		return $macAddress;
	}
}

我们重写了yii\base\BaseObject的init方法,所以会在项目初始化去验证init内容

如果key.lic和licence.lic能够匹配上,通过\Yii::$app->getSecurity()->decryptByKey($licence, $key);这一串代码,那么就实现了授权。为什么需要mac地址,因为这里布置在多个的docker容器里面,ppt和同声传译服务需要调度,这里是为后面的业务做唯一性。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值