Google reCAPTCHA

建立時間: 2016-10-08 12:05:21
更新時間: 2016-10-08 12:05:21

reCAPTCHA

reCAPTCHA是google的網頁驗證機制

比起傳統的驗證扭曲的文字

它可以讓機器人難以破解驗證

相信看到這張圖片

應該就不陌生

 

建立一個reCAPTCHA API

首先要有一個google帳號來管理reCAPTCHA

然後到reCAPTCHA的官網建立一個新的reCAPTCHA

填入自訂的AP名稱及網站Domain Name

 

建立完成後

會看到Site KeySecret Key

這些待會會用到

 

將reCAPTCHA放到網頁上

首先依照官網的指示

把JavaScript載入網頁的</head>內

 <script src='https://www.google.com/recaptcha/api.js'></script>

 

接著把reCAPTCHA放到要顯示的位置

在data-sitekey屬性中填入先前的site key

 <div class="g-recaptcha" data-sitekey="your-sitekey"></div>

 

到這邊為止

我們已經能夠在網頁上載入reCAPTCHA來顯示了

 

 

透過JavaScript操作reCAPTCHA

雖然前面能夠顯示reCAPTCHA

但是我們需要能夠透過JavaScript完整操作

所以要使用官方建議的延遲載入

並在載入後執行一個callback讓我們能夠取得reCAPTCHA的載入事件

進一步的在載入後做一些reCAPTCHA的設定

所以我們要把前面的JavaScript載入做一些修改

 <script src='https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit' async defer></script>

 

 

取得載入事件(onloadCallback)後

我們就能在載入後

用JavaScript做一些事情

 // 完整載入reCAPTCHA後, 執行onloadCallback
 var onloadCallback = function() {
 	console.log('reCAPTCHA is ready');
 
 	/**
 	 * reCAPTCHA設定
 	 * 設定sitekey, 主題顏色
 	 */
 	grecaptcha.render('reCAPTCHA', {
 		'sitekey': 'your-sitekey',
 		'theme': 'dark'
 	});
 }
 

 

更多設定可參考官方文件grecaptcha.render parameter

 

取得驗證完的response

首先要先了解reCAPTCHA的驗證流程

驗證流程如下

  1. 使用者開始驗證
  2. 驗證完回傳一個response到網頁前端
  3. 前端將這個response傳到後端
  4. 後端判定這個response是否合法
  5. 後端回傳判定結果到前端

 

從流程可以得知

我們要在使用者驗證完之後取得google回傳一個變數

也就是上面提到的response

官方文件中共提到三種方式可以取得repsonse

  1.  使用者完成驗證後, response會存在表單變數g-recaptcha-response中, 表單POST到後端後即可取得
  2.  在JavaScript中的grecaptcha.getResponse()取得
  3.  在JavaScript一開始的grecaptcha.render()中設定取得response的function, 使用者驗證完後就執行這個function

 

第一種方式

直接POST表單到後端取得表單g-recaptcha-response變數即可

 

第二種方式

 // 完整載入reCAPTCHA後, 執行onloadCallback
 var onloadCallback = function() {
 	console.log('reCAPTCHA is ready');
 
 	// reCAPTCHA設定
 	grecaptcha.render('reCAPTCHA', {
 		'sitekey': 'your-sitekey',
 		'theme': 'dark'
 		'callback': verfyComplete
 	});
 }
 
 // 使用者驗證完後, 將response結果存入reCAPTCHA_response
 var verfyComplete = function(response) {
 	window.reCAPTCHA_response = response;
 }

 

第三種方式

 var reCAPTCHA_response = grecaptcha.getResponse();

 

到這裡為止

我們已經完成三分之二了

接著只要剩下後端的判定

 

後端的判定

首先到reCAPTCHA的github取得後端的程式

可以使用composer取得或是直接下載zip檔

 

接著很簡單

載入程式後將前面的secret key帶入

並且將前端傳來的response(下方範例的$gRecaptchaResponse)帶入veritfy判定函式中

另一個帶入變數$remoteIp只是使用者的IP(官方文件有寫到可有可無)

接著依照判定結果回傳自己要的資訊到前端即可

 

錯誤代碼的詳細資訊可參考官方文件

 <?php
 	require('recaptcha-master/src/autoload.php');
 	$secret = 'your-secret-key';	// reCAPTCHA secret key
 	$recaptcha = new \ReCaptcha\ReCaptcha($secret);
 	$resp = $recaptcha->verify($gRecaptchaResponse, $remoteIp);
 
 	if($resp->isSuccess()){
 		// 判定為合法的驗證
 		return 'reCAPTCHA verified';
 	}else{
 		// 判定為不合法的驗證, 回傳錯誤碼
 		$errors = $resp->getErrorCodes();
 		return $errors;
 	}
 ?>

 

重新驗證

有時候使用者會需要重新啟動reCAPTCHA驗證

這時只要使用grecaptcha.reset()函式即可

 grecaptcha.reset();

 

完整範例

前面寫的分了好幾步驟可能有點亂

可以參考以下的前後端範例

 

index.html(前端)

這邊取得reponse的方式為使用grecaptcha.getResponse()函式

 <!DOCTYPE html>
 <html lang="en">
 <head>
 	<meta charset="UTF-8">
 	<title>Document</title>
 	<script src="https://code.jquery.com/jquery-3.1.0.min.js"></script>
 	<script src='https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit' async defer></script>
 	<script>
 		// 完整載入reCAPTCHA後, 執行onloadCallback
 		var onloadCallback = function() {
 			console.log('reCAPTCHA is ready');
 
 			// reCAPTCHA設定
 			grecaptcha.render('reCAPTCHA', {
 				'sitekey': 'your-site-key',
 				'theme': 'dark'
 			});
 		}
 
 		$(function() {
 			$('#submit-btn').click(function() {
 
 				// 取得使用者驗證後的response
 				var reCAPTCHA_response = grecaptcha.getResponse();
 
 				// 將response傳到後端
 				$.ajax({
 					url: 'api.php',
 					type: 'POST',
 					dataType: 'json',
 					data: {
 						action: 'formSubmit',
 						response: reCAPTCHA_response,
 					},
 					success: function(data){
 						if(data == 'reCAPTCHA verified'){
 							alert('驗證成功!')
 						}else if(data == 'reCAPTCHA is not verified'){
 							alert('驗證失敗!');
 						}
 					},
 					error: function(err){
 						console.log(err);
 					}
 				});
 			});
 
 			// 重新啟動reCAPTCHA驗證
 			$('#reset-btn').click(function() {
 				grecaptcha.reset();
 			});
 		});
 	</script>
 </head>
 <body>
 	<h1>
 		reCAPTCHA Demo
 	</h1>
 	<br>
 
 	<div id="myForm">
 		<div id="verficationContainer">
 			<div id="reCAPTCHA"></div>
 		</div>
 		<br>
 
 		<button id="reset-btn" type="submit">
 			Reset reCAPTCHA
 		</button>		
 
 		<button id="submit-btn" type="submit">
 			Submit
 		</button>
 	</div>
 </body>
 </html>

 

api.php(後端)

 <?php
 	if($_POST["action"]){
 		switch($_POST["action"]){
 			case "formSubmit":
 				echo json_encode(formSubmit(
 					$_POST["response"]
 				));
 				break;
 		}
 	}
 
 	function formSubmit($gRecaptchaResponse){
 		require('recaptcha-master/src/autoload.php');
 		$secret = 'yoru-secret-key';
 		$recaptcha = new \ReCaptcha\ReCaptcha($secret);
 		$resp = $recaptcha->verify($gRecaptchaResponse, $remoteIp);
 		
 		if($resp->isSuccess()){
 			return 'reCAPTCHA verified';
 		}else{
 			$errors = $resp->getErrorCodes();
 			return 'reCAPTCHA is not verified';
 		}
 	}
 ?>