Initial commit,修正
This commit is contained in:
+339
@@ -0,0 +1,339 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Fm453
|
||||
* @site www.hiluker.com
|
||||
* @remark:接口通信证书处理
|
||||
*/
|
||||
defined('HI_FM') or exit("Access Denied");
|
||||
|
||||
fm_load()->fm_func('fm');
|
||||
fm_load()->fm_func('file');
|
||||
|
||||
//判断某用户证书是否存在
|
||||
/*
|
||||
@username 用户名
|
||||
*/
|
||||
|
||||
function fmFunc_cert_exist($username)
|
||||
{
|
||||
global $_GPC;
|
||||
global $_HI;
|
||||
global $_FM;
|
||||
$file = $_HI['apiCertPath'].$username.'.php';
|
||||
if(file_exists($file)){
|
||||
$cert = require($file);
|
||||
return $cert;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//登陆前,根据来路判断访问是否合规
|
||||
/*
|
||||
@username 用户名
|
||||
@ip 来路IP
|
||||
@domain 来路域名
|
||||
*考虑到CDN加速导致IP变化的原因,域名或IP有一个符合规则即可
|
||||
*/
|
||||
|
||||
function fmFunc_cert_beforeLogin($cert,$ip,$domain)
|
||||
{
|
||||
global $_GPC;
|
||||
global $_HI;
|
||||
global $_FM;
|
||||
|
||||
if(!is_array($cert) && !empty($cert)){
|
||||
//未引入证书时,不判断
|
||||
return true;
|
||||
}elseif(empty($ip) && empty($domain)){
|
||||
//ip与domain均未传入时,不判断
|
||||
return true;
|
||||
}
|
||||
$ips = isset($cert['suIp']) ? $cert['suIp'] : false;
|
||||
$domains = isset($cert['suDomain']) ? $cert['suDomain'] : false;
|
||||
$username = isset($cert['api']) ? $cert['api'] : false;
|
||||
if(!$ips || !$domains || !$username){
|
||||
//没有有效的证书配置时,不判断
|
||||
return true;
|
||||
}
|
||||
|
||||
//为fm453本地开发放行,为公共密钥publicapi放行
|
||||
if($username == 'vcms.localhost' || $username == 'publicapi') {
|
||||
return true;
|
||||
}
|
||||
|
||||
//判断ip与domain的合法性
|
||||
if(!in_array($ip,$ips) && !in_array($domain,$domains)){
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//登陆后,更新证书
|
||||
/*
|
||||
*有则更新,无则创建
|
||||
*/
|
||||
function fmFunc_cert_afterLogin(){
|
||||
global $_GPC;
|
||||
global $_HI;
|
||||
global $_FM;
|
||||
if(!isset($_FM['user']['name'])){
|
||||
return false;
|
||||
}
|
||||
|
||||
$_FM['viaDomain'] = isset($_FM['viaDomain']) ? $_FM['viaDomain'] : fmFunc_server_via_domain();
|
||||
$_FM['viaIp'] = isset($_FM['viaIp']) ? $_FM['viaIp'] : fmFunc_server_via_ip();
|
||||
|
||||
$connection = yii::$app->db;
|
||||
//客户侧是否请求刷新token;否,则直接取token值后返回(应对同一账号同一站点多模块使用的情况)(同一账号,同一站点对应同一token;同一账号可拥有多个token)
|
||||
if(!isset($_GET['refreshToken']) || empty($_GET['refreshToken'])){
|
||||
$sql = "SELECT `accesstoken` FROM c_access WHERE username = :username AND ip = :ip AND domain = :domain ORDER BY id ASC";
|
||||
$params = array();
|
||||
$params[':username'] = $_FM['user']['name'];
|
||||
$params[':ip'] = $_FM['viaIp'];
|
||||
$params[':domain'] = $_FM['viaDomain'];
|
||||
//$AccessToken = fmFunc_pdo_yii_fetchcolumn($connection,$sql, $params);
|
||||
$AccessToken = fmFunc_pdo_yii_fetchcolumn($connection,$table='c_access', $column='accesstoken', $conditions = 'username = :username AND ip = :ip AND domain = :domain ORDER BY id ASC', $params);
|
||||
$_FM['token'] = $AccessToken;
|
||||
|
||||
//cert证书文件
|
||||
//如果没有,创建之;如果有,更新其中的token
|
||||
$username = $_FM['user']['name'];
|
||||
$cert = fmFunc_cert_exist($username);
|
||||
if(!$cert){
|
||||
$cert = array();
|
||||
$cert['id'] = $_FM['user']['uid'];
|
||||
$cert['siteId'] = $_FM['timestamp'];
|
||||
$cert['suIp'] = array($_FM['viaIp']);
|
||||
$cert['siteName'] = '';
|
||||
$cert['suDomain'] = array($_FM['viaDomain']);
|
||||
$cert['siteUrl'] = '';
|
||||
$cert['api'] = $username;
|
||||
$cert['code'] = '';
|
||||
$cert['token'] = $AccessToken;
|
||||
$cert['status'] = '0';
|
||||
$cert['remark'] = '新创建待审核,创建时间:'.date('Y-m-d H:i:s',$_FM['timestamp']);
|
||||
}
|
||||
$_FM['apiCert'] = $cert;
|
||||
fmFunc_cert_write($username,$cert);
|
||||
|
||||
if($AccessToken) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//生成一个新AccssToken
|
||||
/*
|
||||
*生成方法:
|
||||
@md5: 用户名username+编码useruid+当前时间戳timestamp+失效时间expiretime+随机混淆码randchars 拼接
|
||||
*/
|
||||
$randchars = randchars(5);
|
||||
$content = array();
|
||||
$content[] = $_FM['user']['name'];
|
||||
$content[] = $_FM['user']['uid'];
|
||||
$content[] = $_FM['timestamp'];
|
||||
$content[] = $expiretime = 3600 * 24 * 30;
|
||||
$content[] = $randchars;
|
||||
$_content = iserializer($content);
|
||||
$AccessToken = md5($_content);
|
||||
|
||||
$_FM['token'] = $AccessToken;
|
||||
|
||||
//在c_access表中记录登陆对应的有效token
|
||||
$initdata = array();
|
||||
$initdata['accesstoken'] = $AccessToken;
|
||||
$initdata['updatetime'] = $_FM['timestamp'];
|
||||
$initdata['expiretime'] = $_FM['timestamp']+$expiretime;
|
||||
$initdata['hashchars'] = $randchars;
|
||||
|
||||
$sql = "SELECT `id` FROM c_access WHERE username = :username AND ip = :ip AND domain = :domain ORDER BY id ASC";
|
||||
$params = array();
|
||||
$params[':username'] = $_FM['user']['name'];
|
||||
$params[':ip'] = $_FM['viaIp'];
|
||||
$params[':domain'] = $_FM['viaDomain'];
|
||||
$hasId = fmFunc_pdo_yii_fetch($connection,$sql, $params);
|
||||
if($hasId) {
|
||||
$condition = 'username = :username AND ip = :ip AND domain = :domain';
|
||||
fmFunc_pdo_yii_update($connection, 'c_access', $initdata, $condition, $params);
|
||||
}else{
|
||||
$initdata['username'] = $_FM['user']['name'];
|
||||
$initdata['uid'] = $_FM['user']['uid'];
|
||||
$initdata['userType'] = 2; //客户系统侧的用户登陆,统一归为user类型(接口使用者)
|
||||
$initdata['ip'] = $_FM['viaIp'];
|
||||
$initdata['domain'] = $_FM['viaDomain'];
|
||||
$initdata['data'] = $_content;
|
||||
$initdata['create_time'] = date('y-m-d H:i:s',$_FM['timestamp']);
|
||||
fmFunc_pdo_yii_insert($connection, 'c_access', $initdata);
|
||||
}
|
||||
|
||||
//cert证书文件进一步校验
|
||||
//如果没有,创建之;如果有,更新其中的token
|
||||
$username = $_FM['user']['name'];
|
||||
$cert = fmFunc_cert_exist($username);
|
||||
if(!$cert){
|
||||
$cert = array();
|
||||
$cert['id'] = $_FM['user']['uid'];
|
||||
$cert['siteId'] = $_FM['timestamp'];
|
||||
$cert['suIp'] = array($_FM['viaIp']);
|
||||
$cert['siteName'] = '';
|
||||
$cert['suDomain'] = array($_FM['viaDomain']);
|
||||
$cert['siteUrl'] = '';
|
||||
$cert['api'] = $username;
|
||||
$cert['code'] = '';
|
||||
$cert['token'] = $AccessToken;
|
||||
$cert['status'] = '0';
|
||||
$cert['remark'] = '新创建待审核,创建时间:'.date('Y-m-d H:i:s',$_FM['timestamp']);
|
||||
}elseif(is_array($cert)){
|
||||
$cert['token'] = $AccessToken;
|
||||
$cert['updatetime'] = '更新时间:'.date('Y-m-d H:i:s',$_FM['timestamp']);
|
||||
}
|
||||
fmFunc_cert_write($username,$cert);
|
||||
}
|
||||
|
||||
//为指定用户写证书
|
||||
/*
|
||||
@username 用户名
|
||||
@cert 证书内容
|
||||
*/
|
||||
|
||||
function fmFunc_cert_write($username,$cert)
|
||||
{
|
||||
global $_GPC;
|
||||
global $_HI;
|
||||
global $_FM;
|
||||
|
||||
if(!$username){
|
||||
return false;
|
||||
}
|
||||
|
||||
$file = $_HI['apiCertPath'].$username.'.php';
|
||||
|
||||
$content = "<?php";
|
||||
$content .= "\r\n";
|
||||
$content .= "/*";
|
||||
$content .= "\r\n";
|
||||
|
||||
$content .= "* 通讯证书文件";
|
||||
$content .= "\r\n";
|
||||
|
||||
$content .= "@status 站点状态,-1禁止 0只读 1可用";
|
||||
$content .= "\r\n";
|
||||
$content .= "@siteId 站点ID";
|
||||
$content .= "\r\n";
|
||||
$content .= "@suIp 允许访问的IP";
|
||||
$content .= "\r\n";
|
||||
$content .= "@suDomain 允许访问的域名";
|
||||
$content .= "\r\n";
|
||||
$content .= "@api 接口用户名(站点用户名)";
|
||||
$content .= "\r\n";
|
||||
$content .= "@code 用户授权码";
|
||||
$content .= "\r\n";
|
||||
$content .= "@token 接口通讯的accesstoken文件";
|
||||
$content .= "\r\n";
|
||||
|
||||
$content .= "*/";
|
||||
$content .= "\r\n";
|
||||
$content .= "\$cert = array();";
|
||||
$content .= "\r\n";
|
||||
foreach($cert as $k=>$v){
|
||||
if(!is_array($v)) {
|
||||
$content .= "\$cert['".$k."'] = '".(string)$v."';";
|
||||
}else{
|
||||
$content .= "\$cert['".$k."'] = array(";
|
||||
$len = count($v);
|
||||
for($i = $len;$i>0;$i--){
|
||||
if($i>1) {
|
||||
$content .= "'".(string)$v[$i-1]."',";
|
||||
}elseif($i==1) {
|
||||
$content .= "'".(string)$v[$i-1]."'";
|
||||
}
|
||||
}
|
||||
$content .= ");";
|
||||
}
|
||||
$content .= "\r\n";
|
||||
}
|
||||
$content .= "return \$cert;";
|
||||
$content .= "\r\n";
|
||||
|
||||
fmFunc_file_write($file,$content);
|
||||
}
|
||||
|
||||
/*__________________________________________________*/
|
||||
//根据请求数据返回通讯授权结果(0为正常,>0表示错误代码)
|
||||
/*
|
||||
*判断机制:
|
||||
(1)get方式接收到username与accesstoken,判断是否匹配
|
||||
(2)username对应的证书文件是否存在
|
||||
(3)根据证书检测是否合规的访问
|
||||
*/
|
||||
function fmFunc_cert_checkAuth(){
|
||||
global $_GPC;
|
||||
global $_HI;
|
||||
global $_FM;
|
||||
//检查appid
|
||||
if(!isset($_FM['get']['appid'])){
|
||||
return 45300205; //未指定有效的appid
|
||||
}elseif(empty($_FM['get']['appid'])){
|
||||
return 45300205; //未指定有效的appid
|
||||
}
|
||||
|
||||
//检查accesstoken
|
||||
if(!isset($_FM['get']['accesstoken'])){
|
||||
return 45300204; //未指定有效的accesstoken
|
||||
}elseif(empty($_FM['get']['accesstoken'])){
|
||||
return 45300204; //未指定有效的accesstoken
|
||||
}
|
||||
|
||||
//检查appid与accesstoken是否匹配
|
||||
$username = $_FM['get']['appid'];
|
||||
$accesstoken = $_FM['get']['accesstoken'];
|
||||
$connection = yii::$app->db;
|
||||
|
||||
$sql = "SELECT `id` FROM c_access WHERE username = :username AND accesstoken = :accesstoken ";
|
||||
$params = array();
|
||||
$params[':username'] = $username;
|
||||
$params[':accesstoken'] = $accesstoken;
|
||||
$hasId = fmFunc_pdo_yii_fetch($connection,$sql, $params);
|
||||
if(!$hasId){
|
||||
return 45300206; //不匹配
|
||||
}
|
||||
|
||||
|
||||
//设置用户为登陆状态
|
||||
$_FM['user']['name'] = $username;
|
||||
// 使用指定用户名获取用户身份实例
|
||||
$User = new common\models\User;
|
||||
$identity = $User->findOne(['username' => $_FM['user']['name']]);
|
||||
$_FM['user']['uid'] = $identity->id;
|
||||
// 登录用户,有效期30d
|
||||
$duration = 3600 * 24 * 30;
|
||||
Yii::$app->user->login($identity, $duration);
|
||||
|
||||
//查询服务器证书
|
||||
$cert = fmFunc_cert_exist($username);
|
||||
if(!$cert){
|
||||
return 45300104; //未查询到服务器证书
|
||||
}
|
||||
|
||||
//检查证书有效性
|
||||
$ips = isset($cert['suIp']) ? $cert['suIp'] : false;
|
||||
$domains = isset($cert['suDomain']) ? $cert['suDomain'] : false;
|
||||
$api = (isset($cert['api']) && !empty($cert['api'])) ? $cert['api'] : false;
|
||||
if((!$ips && !$domains) || !$api){
|
||||
return 45300105; //无效的证书
|
||||
}
|
||||
|
||||
//来路域名与IP
|
||||
$_FM['viaDomain'] = isset($_FM['viaDomain']) ? $_FM['viaDomain'] : fmFunc_server_via_domain();
|
||||
$_FM['viaIp'] = isset($_FM['viaIp']) ? $_FM['viaIp'] : fmFunc_server_via_ip();
|
||||
|
||||
//为fm453本地开发放行,为公共密钥publicapi放行,其他来路均需判断合法性
|
||||
if($username != 'vcms.localhost' && $username != 'publicapi') {
|
||||
//判断ip与domain的合法性
|
||||
if(!in_array($_FM['viaIp'],$ips) && !in_array($_FM['viaDomain'],$domains)){
|
||||
return 45300101; //来源IP或域名不在白名单中
|
||||
}
|
||||
}
|
||||
|
||||
$_FM['apiCert'] = $cert;
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user