-
背景
最近,項目后臺上線后,有人覺得登錄頁的四位驗證碼有時候看不出來,需要刷新好幾次填對;于是在搜索滑動驗證時注意到了阿里云的這個人機驗證功能;雖然也有好多網友提供實現方法,但是經過自己的操作,覺得自己整理一番,不僅可以幫助新手,也能作為自己以后的經驗備忘,歡迎指摘 ...
了解概念,不然也找不到自己選擇這個功能的理由吧:
滑動驗證(No-Captcha,簡稱NC)
,是阿里巴巴集團打破傳統驗證碼技術推出的最新人機識別服務。阿里云的滑動驗證采用先進的風險分析引擎來區分來自人類與機器人的訪問行為。用戶通過類似滑動解鎖的方式來通過人機驗證,對用戶來說無需思考即可通過人機識別(圖靈測試)的挑戰。環境:
框架: ThinkPHP5.1
系統:Nginx、Win10、CentOS7.2
㈠ 前期準備
- 首先,建議閱讀【
人機滑動驗證 官方文檔
】,鄙人覺得里面介紹的很詳細,作為指導博文,不可能全給摘過來的 - 既然考慮到使用人家的服務,當然得了解一下是不是免費啥的唄,0.002元/條,好在也是不貴吧?
- 【
創建 AccessKey (指導)
】,請使用子賬號(RAM用戶)AccessKey,并為子賬號授予云盾人機驗證權限(AliyunYundunAFSFullAccess) - 根據 【
滑動驗證 —— 快速入門
】,在【云盾人機驗證控制臺
】開通、配置
㈡ 前端接入代碼集成
首先,給出官方文檔介紹【 滑動驗證前端代碼集成文檔-PCWEB版
】,然后對比我的實際操作代碼即可
- Html 核心代碼 (至于樣式的優化,文檔中有,自行融合唄)
<!-- 國內使用 -->
<script type="text/javascript" charset="utf-8" src="http://g.alicdn.com/sd/ncpc/nc.js?t=2015052012"></script>
<div id="your-dom-id" class="layui-form-item nc-container"></div>
<input type="hidden" class="nc_token" name="nc_token" value="X">
- js 核心代碼:
var nc_appkey = "Your appkey";//寫入自己的 appkey
var nc_token = [nc_appkey , (new Date()).getTime(), Math.random()].join(':');
var NC_Opt =
{
renderTo: "#your-dom-id",
appkey: nc_appkey ,
scene: "nc_login",
token: nc_token,
customWidth: 300,
trans:{"key1":"code0"},
elementID: ["usernameID"],
is_Opt: 0,
language: "cn",
isEnabled: true,
timeout: 3000,
times:5,
callback: function (data) {
//window.console && console.log(nc_token);
//console.log('sss',data);
//TODO 此處 toUrl 即為后臺驗證鏈接,根據自己的業務定義即可
var toUrl = "{:url('cms/login/ajaxAfsCheck')}";
$.post(
toUrl,
data,
function (result) {
if (result.status == 1) {
$(".nc_token").val(nc_token);
} else {
//失敗
layer.msg(result.message);
}
}, "JSON");
}
};
var nc = new noCaptcha(NC_Opt);
nc.upLang('cn', {
_startTEXT: "請按住滑塊,拖動到最右邊",
_yesTEXT: "驗證通過",
_error300: "哎呀,出錯了,點擊<a href=\"javascript:__nc.reset()\">刷新</a>再來一次",
_errorNetwork: "網絡不給力,請<a href=\"javascript:__nc.reset()\">點擊刷新</a>",
});
㈢ 服務端代碼集成
此時可以根據 【滑動驗證服務端代碼集成文檔
】,進行整合處理
- 在【
云盾·人機控制臺
】下載對應語言的SDK
以鄙人的ThinkPHP5.1.2框架環境
,服務端 SDK代碼放置位置參考:
- 應用服務器 請求處理類的設計:
此驗證方法即為前端js中回調所觸發的請求鏈接地址
注意:YOUR ACCESS_KEY、YOUR ACCESS_SECRET請替換成您的阿里云子賬號(RAM用戶)的 accesskey id和secret ; YOUR APP_KEY 寫入自己的 appkey
/**
* ajax 測試阿里云滑動驗證
* @param Request $request
* TODO YOUR ACCESS_KEY、YOUR ACCESS_SECRET請替換成您的阿里云子賬號(RAM用戶)的 accesskey id和secret
* YOUR APP_KEY : 寫入自己的 appkey
*/
public function ajaxAfsCheck(Request $request)
{
if ($request->isPost()) {
$postData = $request->post();
include_once '../extend/aliyun/aliyun-php-sdk-core/Config.php';
$iClientProfile = \DefaultProfile::getProfile("cn-hangzhou", "YOUR ACCESS_KEY",
"YOUR ACCESS_SECRET");
$client = new \DefaultAcsClient($iClientProfile);
\DefaultProfile::addEndpoint("cn-hangzhou", "cn-hangzhou", "afs", "afs.aliyuncs.com");
$request = new Afs\AuthenticateSigRequest();
$ip = get_real_ips(); //自定義的一個獲取IP地址的方法
$request->setSessionId($postData["csessionid"]);// 必填參數,從前端獲取,不可更改,android和ios只傳這個參數即可
$request->setToken($postData['token']);// 必填參數,從前端獲取,不可更改
$request->setSig($postData['sig']);// 必填參數,從前端獲取,不可更改
$request->setScene('nc_login');// 必填參數,從前端獲取,不可更改
$request->setAppKey("YOUR APP_KEY");//必填參數,后端填寫(寫入自己的 appkey)
$request->setRemoteIp($ip);//必填參數,后端填寫
$response = $client->getAcsResponse($request);//返回code 100表示驗簽通過,900表示驗簽失敗
$opTag = ($response->Code === 100) ? 1 : 0;
$message = ($response->Code === 100)? "驗簽通過":"驗簽失敗";
if ($opTag){
Session::set('NC_TOKEN',$postData['token']);
}else{
Session::set('NC_TOKEN','NULL');
}
} else {
$opTag = 0;
$message = "請求不合法";
}
return showMsg($opTag, $message,$response); //就是返回 json_encode()處理后的數據
}
㈣ 后期處理以及效果
在前面的操作完成后,按照完整的業務處理邏輯,緊接著就是要處理登錄按鈕的觸發事件了
> 鄙人的操作是:
在登錄按鈕觸發的 ajax 請求驗證中;
判斷當前 Session 中的 "NC_TOKEN " 是否和 前端隱藏域傳來的 "nc_token" 值相等 ;
如果相等,說明已成功滑動驗證通過,繼而判斷賬號和密碼是否能成功登錄;
反之提示刷新再次進行驗證 ...
-
執行效果圖:
附錄:
- 頻繁查看的鏈接:【
云盾·人機控制臺
】 - 一方面覺得寫得太詳細了,有點顯得冗雜了,其實看文檔仔細點也是沒問題的
提示:多留意一下,我在"㈠ 前期準備"
中提及的信息,尤為重要!! - 補充,后臺獲取IP 地址的函數:
/**
* 此方法返回用戶的IP地址,同時如果擁有代理IP,將會以逗號追加在后面
* 如果只取用當前IP,可參考 :
* $ips = explode(',', $bargainModel->get_real_ips());
* $ip = $ips[0];
*/
function get_real_ips()
{
global $ip;
if (getenv("HTTP_CLIENT_IP")) {
$ip = getenv("HTTP_CLIENT_IP");
} else if (getenv("HTTP_X_FORWARDED_FOR")) {
$ip = getenv("HTTP_X_FORWARDED_FOR");
} else if (getenv("REMOTE_ADDR")) {
$ip = getenv("REMOTE_ADDR");
} else {
$ip = "NULL";
}
return $ip;
}