Use reCaptcha with ZK"

From Documentation
m (correct highlight (via JWB))
 
(29 intermediate revisions by 2 users not shown)
Line 1: Line 1:
 
{{Template:Smalltalk_Author|
 
{{Template:Smalltalk_Author|
 
|author=Hawk Chen, Engineer, Potix Corporation
 
|author=Hawk Chen, Engineer, Potix Corporation
|date= ?
+
|date= May 9, 2017
|version=ZK 8.0.4
+
|version=ZK 8  
 
}}
 
}}
  
 
= Introduction =  
 
= Introduction =  
Google [https://www.google.com/recaptcha/intro/invisible.html reCaptach] is an easy to use and free service that protects your site from spam and bot. Users usually jsut
+
Google [https://www.google.com/recaptcha/intro/invisible.html reCAPTCHA] is an easy to use and free service that protects your site from spam and bot. Users usually just need one click to pass the check instead of reading twisted words in [https://www.zkoss.org/wiki/ZK_Component_Reference/Essential_Components/Captcha ZK Captcha]. This article will show you how to use it within ZK framework.
  
https://developers.google.com/recaptcha/docs/start
+
[[File:recaptcha.png | center]]
See also: [https://www.zkoss.org/wiki/ZK_Component_Reference/Essential_Components/Captcha Captcha]
 
  
 
= Get reCaptcha =
 
= Get reCaptcha =
Please follow Google's guide to get reCaptcha API key: https://developers.google.com/recaptcha/docs/start
+
Please follow Google's guide to get reCaptcha API key: https://developers.google.com/recaptcha/docs/start.
 +
 
 +
There are 2 types:
 +
 
 +
* reCAPTCHA v2
 +
* Invisible reCAPTCHA
 +
 
 +
Please check Google's document to know which type you need. You need 2 different API key to for 2 types.
  
 
= How to Apply =
 
= How to Apply =
== Include recaptcha API & Configuration ==
+
== Include reCAPTCHA API & Configuration ==
  
 
<source lang='xml'>
 
<source lang='xml'>
<zk xmlns:n="native" xmlns:c="client">
+
<zk xmlns:c="client" xmlns:x="xhtml">
<script type="text/javascript" src='https://www.google.com/recaptcha/api.js'  
+
<script type="text/javascript" src='https://www.google.com/recaptcha/api.js' defer="true" />
defer="true" />
+
...
..
+
<x:div id="recaptcha" class="g-recaptcha"
 +
data-sitekey="your-key"
 +
data-callback="afterValidate" />
 +
</source>
  
<n:div class="g-recaptcha" data-sitekey="6Lcj5AYTAAAAAHp_ATdyZcWkMi7lzO_JZPMhYj4S"
+
If the key is correct, you should see the reCaptcha is rendered. If not, open developer tool / Console tab to check an error.
data-callback="afterValidate" />
+
 
 +
==  Verify a User Response ==
 +
You also need to specify a callback function name at <code>data-callback</code> attribute to verify a user's response to a reCAPTCHA challenge at the server side.
 +
 
 +
=== MVC Pattern ===
 +
<source lang='xml'>
 +
<zk xmlns:c="client" xmlns:x="xhtml" highlight='4' >
 +
<script type="text/javascript" src='https://www.google.com/recaptcha/api.js' defer="true" />
 +
<script><![CDATA[
 +
function afterValidate(response){
 +
zk.Widget.$('$recaptcha').fire('onUserRespond',{'response':response}, {toServer:true});
 +
}
 +
]]>
 +
</script>
 +
<x:div id="recaptcha" class="g-recaptcha"  
 +
data-sitekey="${sitekey}"
 +
data-callback="afterValidate" />
 +
</zk>
 
</source>
 
</source>
  
== Check Verification Result ==
+
Here we fire an event, <code>onUserRespond</code>, with [https://www.zkoss.org/wiki/ZK_Client-side_Reference/Notifications/Widget_Events#Event_Firing ZK widget API] to send a reCAPTCHA response to the server.
 +
 
 +
Then we can verify the response according to https://developers.google.com/recaptcha/docs/verify. The verified result is a JSON object, and you can get the success result by key '''success'''.
 +
<source lang='java' highlight='8, 10, 11'>
 +
public class RecaptchaComposer extends SelectorComposer<Component> {
 +
 
 +
@Wire
 +
Button submit;
 +
 +
final String SECRET = "6Lcj5AYTAAAAANcaQYWvFkHVSkqR6FsBaCXXw54r"; //from reCaptcha
 +
 +
@Listen("onUserRespond = #recaptcha")
 +
public void verify(Event event) throws Exception{
 +
JSONObject result = RecaptchaVerifier.verifyResponse(SECRET, ((JSONObject)event.getData()).get("response").toString());
 +
if (Boolean.parseBoolean(result.get("success").toString())){
 +
submit.setDisabled(false);
 +
}else{
 +
String errorCode = result.get("error-codes").toString();
 +
//log or show error
 +
}
 +
}
 +
...
 +
}
 +
</source>
 +
* Line 10: <code>RecaptchaVerifier</code> is a helper class that I create to verify a reCAPTCHA response by sending an HTTP request. I make it independent from a composer/ViewModel, so that readers can reuse it. You can check its [https://github.com/zkoss-demo/smalltalk/blob/master/src/main/java/org/zkoss/support/smalltalk/recaptcha/RecaptchaVerifier.java source code].
 +
 
 +
 
 +
=== MVVM Pattern ===
 +
If your controller is a ViewModel, we can send a reCAPTCHA response by [http://books.zkoss.org/zk-mvvm-book/8.0/data_binding/client_binding_api.html client command binding].
 +
<source lang='xml'>
 +
<zk xmlns:c="client" xmlns:x="xhtml" highlight='6'>
 +
<script type="text/javascript"
 +
src='https://www.google.com/recaptcha/api.js' defer="true" />
 +
<script><![CDATA[
 +
function afterValidate(response){
 +
var commandName = jq('#recaptcha').attr('command');
 +
zkbind.$('$recaptcha').command(commandName, {"response":response});
 +
}
 +
]]>
 +
</script>
 +
<x:div id="recaptcha" class="g-recaptcha"
 +
data-sitekey="@load(sitekey)"
 +
data-callback="afterValidate" command="@load(command)" />
 +
</zk>
 +
</source>
  
 
= Reuse =  
 
= Reuse =  
 +
We can encapsulate related elements into a template zul to reuse it in a page.
 +
 +
r[https://github.com/zkoss-demo/smalltalk/blob/master/src/main/webapp/recapcha/recaptchaTemplate.zul ecaptchaTemplate.zul]
 +
<source lang='xml' highlight='12, 13'>
 +
<zk xmlns:c="client" xmlns:x="xhtml">
 +
<script type="text/javascript"
 +
src='https://www.google.com/recaptcha/api.js' defer="true" />
 +
<script><![CDATA[
 +
function afterValidate(response){
 +
var commandName = jq('#recaptcha').attr('command');
 +
zkbind.$('$recaptcha').command(commandName, {"response":response});
 +
}
 +
]]>
 +
</script>
 +
<x:div id="recaptcha" class="g-recaptcha"
 +
data-sitekey="@load(sitekey)"
 +
data-callback="afterValidate" command="@load(command)" />
 +
</zk>
 +
</source>
 +
* Line 12-13: This template accepts 2 paramters: <code>sitekey</code>, <code>command</code>
 +
 +
[https://github.com/zkoss-demo/smalltalk/blob/master/src/main/webapp/recapcha/recaptchaMvvm.zul recaptchaMvvm.zul]
 +
<source lang='xml' highlight='1, 10'>
 +
<?component name="recaptcha" templateURI="recaptchaTemplate.zul"?>
 +
<zk >
 +
<grid id="form" viewModel="@id('vm')@init('org.zkoss.support.smalltalk.recaptcha.RecaptchaVM')" width="400px">
 +
<columns>
 +
<column>Form</column>
 +
</columns>
 +
<rows>
 +
<row>
 +
<cell>
 +
<recaptcha sitekey="6Lcj5AYTAAAAAHp_ATdyZcWkMi7lzO_JZPMhYj4S" command="verify" />
 +
</cell>
 +
</row>
 +
<row>
 +
<button id="submit" disabled="@load(vm.disabled)" onClick="@command('submit')">submit</button>
 +
</row>
 +
</rows>
 +
</grid>
 +
</zk>
 +
</source>
 +
 +
= Invisible reCAPTCHA =
 +
 +
Invisible reCAPTCHA doesn't pop up a checkbox to click.
 +
[[File:invisible-recaptcha.png | center]]
 +
 +
 +
You can just specify <code>data-sitekey</code>, <code>data-callback</code> on a button. When a user clicks the button, reCAPTCHA will verify in the background and call the callback function with a user's response. So that you can verify the response at the server side like the previous example.
 +
 +
<source lang='xml' highlight='5, 20,21'>
 +
<zk xmlns:ca="client/attribute" >
 +
<script type="text/javascript" src='https://www.google.com/recaptcha/api.js' defer="true" />
 +
<script><![CDATA[
 +
function afterValidate(response){
 +
zkbind.$('$recaptcha').command('verify', {"response":response});
 +
}
 +
]]>
 +
</script>
 +
<grid id="form"
 +
viewModel="@id('vm')@init('org.zkoss.support.smalltalk.recaptcha.InvisibleRecaptchaVM')" width="400px">
 +
<columns>
 +
<column>Form</column>
 +
</columns>
 +
<rows>
 +
<row>
 +
other fields
 +
</row>
 +
<row>
 +
    <button id="recaptcha" sclass="g-recaptcha"
 +
    ca:data-sitekey="6Let8B8UAAAAAIe6nfYJbhenKRzmlyAq7s6uXaef"
 +
    ca:data-callback='afterValidate'>
 +
    Submit
 +
    </button>
 +
</row>
 +
</rows>
 +
</grid>
 +
</zk>
 +
</source>
 +
 +
= Source Code =
 +
[https://github.com/zkoss-demo/smalltalk github]
  
  

Latest revision as of 04:34, 20 January 2022

DocumentationSmall Talks2017MayUse reCaptcha with ZK
Use reCaptcha with ZK

Author
Hawk Chen, Engineer, Potix Corporation
Date
May 9, 2017
Version
ZK 8

Introduction

Google reCAPTCHA is an easy to use and free service that protects your site from spam and bot. Users usually just need one click to pass the check instead of reading twisted words in ZK Captcha. This article will show you how to use it within ZK framework.

Recaptcha.png

Get reCaptcha

Please follow Google's guide to get reCaptcha API key: https://developers.google.com/recaptcha/docs/start.

There are 2 types:

  • reCAPTCHA v2
  • Invisible reCAPTCHA

Please check Google's document to know which type you need. You need 2 different API key to for 2 types.

How to Apply

Include reCAPTCHA API & Configuration

<zk xmlns:c="client" xmlns:x="xhtml">
	<script type="text/javascript" src='https://www.google.com/recaptcha/api.js' defer="true" />
	...
	<x:div id="recaptcha" class="g-recaptcha" 
		data-sitekey="your-key"
		data-callback="afterValidate" />

If the key is correct, you should see the reCaptcha is rendered. If not, open developer tool / Console tab to check an error.

Verify a User Response

You also need to specify a callback function name at data-callback attribute to verify a user's response to a reCAPTCHA challenge at the server side.

MVC Pattern

<zk xmlns:c="client" xmlns:x="xhtml" highlight='4' >
	<script type="text/javascript" src='https://www.google.com/recaptcha/api.js' defer="true" />
	<script><![CDATA[ 
		function afterValidate(response){
			zk.Widget.$('$recaptcha').fire('onUserRespond',{'response':response}, {toServer:true}); 
		} 
	]]>
	</script>
	<x:div id="recaptcha" class="g-recaptcha" 
		data-sitekey="${sitekey}"
		data-callback="afterValidate" />	
</zk>

Here we fire an event, onUserRespond, with ZK widget API to send a reCAPTCHA response to the server.

Then we can verify the response according to https://developers.google.com/recaptcha/docs/verify. The verified result is a JSON object, and you can get the success result by key success.

public class RecaptchaComposer extends SelectorComposer<Component> {

	@Wire
	Button submit;
	
	final String SECRET = "6Lcj5AYTAAAAANcaQYWvFkHVSkqR6FsBaCXXw54r"; //from reCaptcha
	
	@Listen("onUserRespond = #recaptcha")
	public void verify(Event event) throws Exception{
		JSONObject result = RecaptchaVerifier.verifyResponse(SECRET, ((JSONObject)event.getData()).get("response").toString());
		if (Boolean.parseBoolean(result.get("success").toString())){
			submit.setDisabled(false);
		}else{
			String errorCode = result.get("error-codes").toString();
			//log or show error
		}
	}
	...
}
  • Line 10: RecaptchaVerifier is a helper class that I create to verify a reCAPTCHA response by sending an HTTP request. I make it independent from a composer/ViewModel, so that readers can reuse it. You can check its source code.


MVVM Pattern

If your controller is a ViewModel, we can send a reCAPTCHA response by client command binding.

<zk xmlns:c="client" xmlns:x="xhtml" highlight='6'>
	<script type="text/javascript"
		src='https://www.google.com/recaptcha/api.js' defer="true" />
	<script><![CDATA[ 
		function afterValidate(response){
			var commandName = jq('#recaptcha').attr('command');
			zkbind.$('$recaptcha').command(commandName, {"response":response});
		} 
	]]>
	</script>
	<x:div id="recaptcha" class="g-recaptcha" 
		data-sitekey="@load(sitekey)"
		data-callback="afterValidate" command="@load(command)" />		
</zk>

Reuse

We can encapsulate related elements into a template zul to reuse it in a page.

recaptchaTemplate.zul

<zk xmlns:c="client" xmlns:x="xhtml">
	<script type="text/javascript"
		src='https://www.google.com/recaptcha/api.js' defer="true" />
	<script><![CDATA[ 
		function afterValidate(response){
			var commandName = jq('#recaptcha').attr('command');
			zkbind.$('$recaptcha').command(commandName, {"response":response});
		} 
	]]>
	</script>
	<x:div id="recaptcha" class="g-recaptcha" 
		data-sitekey="@load(sitekey)"
		data-callback="afterValidate" command="@load(command)" />		
</zk>
  • Line 12-13: This template accepts 2 paramters: sitekey, command

recaptchaMvvm.zul

<?component name="recaptcha" templateURI="recaptchaTemplate.zul"?>
<zk >
	<grid id="form" viewModel="@id('vm')@init('org.zkoss.support.smalltalk.recaptcha.RecaptchaVM')" width="400px">
		<columns>
			<column>Form</column>
		</columns>
		<rows>
			<row>
				<cell>
				<recaptcha sitekey="6Lcj5AYTAAAAAHp_ATdyZcWkMi7lzO_JZPMhYj4S" command="verify" />
				</cell>
			</row>
			<row>
				<button id="submit" disabled="@load(vm.disabled)" onClick="@command('submit')">submit</button>
			</row>
		</rows>
	</grid>
</zk>

Invisible reCAPTCHA

Invisible reCAPTCHA doesn't pop up a checkbox to click.

Invisible-recaptcha.png


You can just specify data-sitekey, data-callback on a button. When a user clicks the button, reCAPTCHA will verify in the background and call the callback function with a user's response. So that you can verify the response at the server side like the previous example.

<zk xmlns:ca="client/attribute" >
	<script type="text/javascript" src='https://www.google.com/recaptcha/api.js' defer="true" />
				<script><![CDATA[ 
		function afterValidate(response){
			zkbind.$('$recaptcha').command('verify', {"response":response});
		} 
	]]>
	</script>
	<grid id="form" 
	viewModel="@id('vm')@init('org.zkoss.support.smalltalk.recaptcha.InvisibleRecaptchaVM')" width="400px">
		<columns>
			<column>Form</column>
		</columns>
		<rows>
			<row>
				other fields
			</row>
			<row>
		    	<button id="recaptcha" sclass="g-recaptcha"
		    		ca:data-sitekey="6Let8B8UAAAAAIe6nfYJbhenKRzmlyAq7s6uXaef"
		    		ca:data-callback='afterValidate'>
		    		Submit
		    	</button>
			</row>
		</rows>
	</grid>	
</zk>

Source Code

github


Comments



Copyright © Potix Corporation. This article is licensed under GNU Free Documentation License.