需要用到的网站
sha加密:https://www.wetools.com/sha
时间戳:https://tool.lu/timestamp/
代码实现
客户端加密:http://domain/?id=id&appid=appid&appsecret=appsecret&ts=ts
请求鉴权:http://domain/?id=id&appid=appid&token=token&ts=ts
<?
interface CredentialStorage{
public function getAppsecretByAppid(String $appid);
}
class IniCredentialStorage implements CredentialStorage{
public function getAppsecretByAppid(String $appid){
$ini_path = str_replace("\\",'/',__DIR__)."/config.ini";
if(!is_file($ini_path)){
throw new \Exception("没有找到配置文件",-1);
}else{
$ini_data = parse_ini_file($ini_path,true);
if(isset($ini_data['auth'][$appid])){
return $ini_data['auth'][$appid];
}else{
throw new \Exception("没有找到匹配的appid",-2);
}
}
}
}
class AuthToken{
const DEFAULT_EXPIRED_TIME_INTERVAL = 1*60;//有效期60s
private $token;
private $createTime;
private $expiredTimeInterval = self::DEFAULT_EXPIRED_TIME_INTERVAL;
public function __construct($token, $createTime){
$this->token = $token;
$this->createTime = $createTime;
}
public function generate($originalUrl, $appId, $password, $timestamp){
$token = sha1($originalUrl.'&appid='.$appId.'&appsecret='.$password.'&ts='.$timestamp);
$this->token = $token;
}
public function getToken(){
return $this->token;
}
public function isExpired(){
if($this->createTime + self::DEFAULT_EXPIRED_TIME_INTERVAL < time()){
return true;
}
return false;
}
public function match($token){
if($token === $this->token){
return true;
}
return false;
}
}
class ApiRequest{
private static $baseUrl;
private static $token;
private static $appid;
private static $timestamp;
public function __construct(){
}
public static function createFromUrl($url){
preg_match('/appid=([\w]+)&token=([\w]+)&ts=([\d]+)/', $url, $matches);
self::$appid = $matches[1];
self::$token = $matches[2];
self::$timestamp = $matches[3];
self::$baseUrl = str_replace("&","",substr($url,0,strlen($url)-strlen($matches[0])));
return new self;
}
public function getBaseUrl(){
return self::$baseUrl;
}
public function getToken(){
return self::$token;
}
public function getAppid(){
return self::$appid;
}
public function getTimestamp(){
return self::$timestamp;
}
}
interface ApiAuthenticator {
public function auth(String $url);
public function auth_url(ApiRequest $apiRequest);
}
class DefaultApiAuthenticatorImpl implements ApiAuthenticator {
private $credentialStorage;
public function __construct(CredentialStorage $credentialStorage) {
$this->credentialStorage = $credentialStorage;
}
public function auth(String $url) {
$apiRequest = ApiRequest::createFromUrl($url);
return self::auth_url($apiRequest);
}
public function auth_url(ApiRequest $apiRequest) {
$appId = $apiRequest->getAppId();
$token = $apiRequest->getToken();
$timestamp = $apiRequest->getTimestamp();
$originalUrl = $apiRequest->getBaseUrl();
$clientAuthToken = new AuthToken($token, $timestamp);
if ($clientAuthToken->isExpired()) {
throw new \Exception("Token is expired.",-3);
}
$password = $this->credentialStorage->getAppsecretByAppid($appId);
$clientAuthToken->generate($originalUrl, $appId, $password, $timestamp);
if (!$clientAuthToken->match($token)) {
throw new \Exception("Token verfication failed.",-4);
}
return true;
}
}
$domain = $_SERVER['REQUEST_SCHEME']."://".$_SERVER['HTTP_HOST'];
$uri = $_SERVER['REQUEST_URI'];
$api_auth_impl = new DefaultApiAuthenticatorImpl(new IniCredentialStorage());
try {
$ret = $api_auth_impl->auth($domain.$uri);
} catch (Exception $e) {
echo $e->getMessage()." ".$e->getCode();
}
鉴权的其它实现
OAuth 2.0 + 网关(如Zuul)+ 认证中心 + AOP实现。还可以通过业务模型规避风险: 1. 充值类业务,就算对方篡改接口,最终结果可以通调用证金融机构的接口验证是否有效,不会给公司带来损失。 2. 如果安全等级非常高,比如提现、转账可以通过发送手机短信,确保是本人操作。 3. 如果是商品信息查询类接口,防止第三方爬取数据,可以在调用一定次数后加入人机验证(输入图片识别码、拼图)。 4. 根据IP限制访问次数。 5. 服务器间调用可以绑定mac地址、IP。 6. 服务器、客户端通过架设私有VPN进行通信,将安全问题转移到VPN上,降低业务复杂度的同时还可以避免加解密带来的性能损耗,提升性能。 7. 调用接口时通过付费方式(如实名认证、银行四要素验证这些调用一次都是要收费的),防止恶意调用。 8. 通过独立加密硬件(如U盾)+ 独立密码验证器(Google验证器)+ 语音识别 + 面部识别(刷脸支付) + 指纹 + 多人同时输入动态秘钥(核打击时发射程序)。 9. 安全性会降低系统性能适可而止。