與reCAPTCHA的Spring集成

有時我們只需要CAPTCHA ,這是一個可悲的事實。 今天,我們將學習如何與reCAPTCHA集成。 因為主題本身并不是特別有趣和高級,所以我們將通過使用Spring Integration處理低級細節來過度設計(?)。 Google決定使用reCAPTCHA的決定取決于兩個因素:(1)這是一種適度良好的CAPTCHA實施方案,具有體面的圖像,并內置了對視力障礙者的支持;(2)外包CAPTCHA可使我們在服務器端保持無狀態。 更不用說我們在圖書數字化方面有所幫助。
第二個原因實際上很重要。 通常,您必須在服務器端生成CAPTCHA,并將預期結果存儲在例如用戶會話中。 當響應返回時,您比較預期的并輸入了CAPTCHA解決方案。 有時我們不想在服務器端存儲任何狀態,更不用說實現驗證碼并不是特別有意義的任務。 因此,擁有現成的和可以接受的東西真是太好了。
完整的源代碼一如既往地可用,我們從一個簡單的Spring MVC Web應用程序開始,沒有任何驗證碼。 reCAPTCHA是免費的,但需要注冊,因此第一步是在我們的示例項目中唱歌并生成您的公鑰/私鑰和填寫的app.properties配置文件。
要在表單上顯示reCAPTCHA并將其包括在表單中,只需添加JavaScript庫:
<div id="recaptcha"> </div>
...
<script src="http://www.google.com/recaptcha/api/js/recaptcha_ajax.js"></script>
并將reCAPTCHA小部件放置在您喜歡的任何位置:
Recaptcha.create("${recaptcha_public_key}","recaptcha",{theme: "white",lang : 'en'}
);
官方文檔非常簡潔,描述性強,因此我不會深入探討這一細節。 當您在<form/>包含此小部件時,當用戶提交時,您將收到兩個額外的字段: recaptcha_response_fieldrecaptcha_challenge_field 。 第一個是用戶鍵入的實際文本,第二個是每個請求生成的隱藏令牌。 reCAPTCHA服務器可能會將它用作會話密鑰,但是我們不在乎,我們要做的就是將此字段進一步傳遞給reCAPTCHA服務器 。 我將使用HttpClient 4對外部服務器執行HTTP請求,并在Scala中執行一些巧妙的模式匹配來解析響應:
trait ReCaptchaVerifier {def validate(reCaptchaRequest: ReCaptchaSecured): Boolean}@Service
class HttpClientReCaptchaVerifier @Autowired()(httpClient: HttpClient,servletRequest: HttpServletRequest,@Value("${recaptcha_url}") recaptchaUrl: String,@Value("${recaptcha_private_key}") recaptchaPrivateKey: String) extends ReCaptchaVerifier {def validate(reCaptchaRequest: ReCaptchaSecured): Boolean = {val post = new HttpPost(recaptchaUrl)post.setEntity(new UrlEncodedFormEntity(List(new BasicNameValuePair("privatekey", recaptchaPrivateKey),new BasicNameValuePair("remoteip", servletRequest.getRemoteAddr),new BasicNameValuePair("challenge", reCaptchaRequest.recaptchaChallenge),new BasicNameValuePair("response", reCaptchaRequest.recaptchaResponse))))val response = httpClient.execute(post)isReCaptchaSuccess(response.getEntity.getContent)}private def isReCaptchaSuccess(response: InputStream) = {val responseLines = Option(response) map {Source.fromInputStream(_).getLines().toList} getOrElse NilresponseLines match {case "true" :: _ => truecase "false" :: "incorrect-captcha-sol" :: _=> falsecase "false" :: msg :: _ => throw new ReCaptchaException(msg)case resp => throw new ReCaptchaException("Unrecognized response: " + resp.toList)}}}class ReCaptchaException(msg: String) extends RuntimeException(msg)
唯一缺少的部分是ReCaptchaSecured特性,它封裝了前面提到的兩個reCAPTCHA字段。 為了使用reCAPTCHA保護任何Web表單,我只是在擴展此模型:
trait ReCaptchaSecured {@BeanProperty var recaptchaChallenge = ""@BeanProperty var recaptchaResponse = ""
}class NewComment extends ReCaptchaSecured {@BeanProperty var name = ""@BeanProperty var contents = ""
}
整個CommentsController.scala并不相關。 但是結果是!
這樣就可以了,但是顯然不是很壯觀。 您如何用Spring Integration替換低級HttpClient調用? ReCaptchaVerifier接口(特征)保持不變,因此不必更改客戶端代碼。 但是我們將HttpClientReCaptchaVerifier重構為兩個單獨的,較小的,相對高級的抽象類:
@Service
class ReCaptchaFormToHttpRequest @Autowired() (servletRequest: HttpServletRequest, @Value("${recaptcha_private_key}") recaptchaPrivateKey: String) {def transform(form: ReCaptchaSecured) = Map("privatekey" -> recaptchaPrivateKey,"remoteip" -> servletRequest.getRemoteAddr,"challenge" -> form.recaptchaChallenge,"response" -> form.recaptchaResponse).asJava}@Service
class ReCaptchaServerResponseToResult {def transform(response: String) = {val responseLines = response.split('\n').toListresponseLines match {case "true" :: _ => truecase "false" :: "incorrect-captcha-sol" :: _=> falsecase "false" :: msg :: _ => throw new ReCaptchaException(msg)case resp => throw new ReCaptchaException("Unrecognized response: " + resp.toList)}}}
請注意,我們不再需要實現ReCaptchaVerifier ,Spring Integration將為我們做到這一點。 我們只需要告訴我們框架應該如何使用上面提取的構建塊。 我想我還沒有描述Spring Integration是什么以及它是如何工作的。 簡而言之,它是企業集成模式的非常純凈的實現(有人可能將其稱為ESB)。 消息流是使用XML描述的,可以嵌入到標準Spring XML配置中:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://www.springframework.org/schema/integration"xmlns:http="http://www.springframework.org/schema/integration/http"xsi:schemaLocation="http://www.springframework.org/schema/integrationhttp://www.springframework.org/schema/integration/spring-integration.xsdhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/integration/httphttp://www.springframework.org/schema/integration/http/spring-integration-http.xsd"><!-- configuration here -->    </beans:beans>
在我們的案例中,我們將描述從HttpClientReCaptchaVerifier Java接口/ Scala特征到reCAPTCHA服務器再返回的消息流。 在必須將ReCaptchaSecured對象轉換為HTTP請求并將HTTP響應轉換為有意義的結果的方式上,該方法從接口透明返回。
<gateway id="ReCaptchaVerifier" service-interface="com.blogspot.nurkiewicz.recaptcha.ReCaptchaVerifier" default-request-channel="reCaptchaSecuredForm"/><channel id="reCaptchaSecuredForm" datatype="com.blogspot.nurkiewicz.web.ReCaptchaSecured"/><transformer input-channel="reCaptchaSecuredForm" output-channel="reCaptchaGoogleServerRequest" ref="reCaptchaFormToHttpRequest"/><channel id="reCaptchaGoogleServerRequest" datatype="java.util.Map"/><http:outbound-gatewayrequest-channel="reCaptchaGoogleServerRequest"reply-channel="reCaptchaGoogleServerResponse"url="${recaptcha_url}"http-method="POST"extract-request-payload="true"expected-response-type="java.lang.String"/><channel id="reCaptchaGoogleServerResponse" datatype="java.lang.String"/><transformer input-channel="reCaptchaGoogleServerResponse" ref="reCaptchaServerResponseToResult"/>
盡管有大量的XML,但是整個消息流還是非常簡單的。 首先我們定義網關 ,它是Java接口和Spring Integration消息流之間的橋梁。 ReCaptchaVerifier.validate()的參數稍后變成一條消息 ,該消息發送到reCaptchaSecuredForm channel 。 ReCaptchaSecured對象從該通道傳遞到ReCaptchaFormToHttpRequest 轉換器 。 轉換器的用途是從ReCaptchaSecured對象到Java映射的兩次轉換,代表一組鍵值對。 稍后,此映射(通過reCaptchaGoogleServerRequest通道)傳遞到http:outbound-gateway 。 該組件的職責是將先前創建的地圖轉換為HTTP請求并將其發送到指定的地址。
響應返回時,將其發送到reCaptchaGoogleServerResponse通道。 ReCaptchaServerResponseToResult轉換器將采取行動,將HTTP響應轉換為業務結果(布爾值)。 最終,轉換器結果被路由回網關。 默認情況下,所有操作都是同步發生的,因此我們仍然可以使用簡單的Java接口進行reCAPTCHA驗證。
信不信由你,這一切正常。 我們不再使用HttpClient (猜測一切都比HttpClient 4 API更好……),而不是一個“巨大”的類,我們有一組較小的,集中的,易于測試的類。 該框架處理接線和底層細節。 精彩?
建筑師的夢想還是開發商的噩夢?
讓我通過引用以上介紹的結論來總結我們的努力:在架構利益與開發有效性之間取得平衡 。 Spring Integration能夠從各種異構源(如JMS,關系數據庫甚至FTP)接收數據,以多種方式聚合,拆分,解析和過濾消息,最后使用最奇特的協議進一步發送消息。 手工編寫所有代碼是一項非常繁瑣且容易出錯的任務。 另一方面,有時我們只是不需要所有的幻想,而弄臟我們的手(例如,通過執行手動HTTP請求并解析響應)則更加簡單易懂。 在盲目地將整個體系結構基于非常高級的抽象或基于手工編碼的低級過程之前,請考慮一下后果和平衡。 沒有解決方案可以解決所有問題。 您發現哪個版本的reCAPTCHA集成更好???
參考資料: 使用…與reCAPTCHA集成... Java社區博客上的JCG合作伙伴 Tomasz Nurkiewicz的Spring Integration 。

翻譯自: https://www.javacodegeeks.com/2012/05/spring-integration-with-recaptcha.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/373185.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/373185.shtml
英文地址,請注明出處:http://en.pswp.cn/news/373185.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

《機器學習基石》---感知機算法

1 推導感知機模型 基本思想是&#xff0c;把特征的線性加權值作為一個分數&#xff0c;根據這個分數與一個門限值的關系來進行分類&#xff1a; 我們加一個特征x0等于1&#xff0c;門限值就可以放到w里面去&#xff0c;得到更簡單的形式&#xff1a; 這就是感知機模型&#xff…

未知錯誤:1000正在終止線程

若在try{} catch{}的catch 塊中加入 catch (Exception ex) { Response.Write(ex.Message); Response.End(); } 則捕獲異常后&#xff0c;提示未知錯誤&#xff1a;1000正在終止線程 轉載于:https://www.cnblogs.com/dennysong/p/5422567.…

分叉并加入Java 7 – JSR 166并發實用程序

Java 7最有趣的改進之一是對并發的更好支持。 使用JSR 166并發實用程序&#xff0c;我們可以對并發進行一些非常有用的改進。 在我看來&#xff0c;fork-join庫在軟件工程中具有很高的實際應用潛力。 Fork and join為算法提供了非常簡單的編程模型&#xff0c;可以將其實現為遞…

linux內核源碼代碼量,Linux內核源代碼數量已經超過1000萬行

Linux版本2.6.27更新后,人們發現,這一內核的源代碼數量已經超過了1000萬行.當然,這些行數僅僅是計算機統計出來的行數,包括空白行,為了代碼的可讀性增加的注釋等,當然Linux和所有的長期項目一樣,隨著時間的推移,舊的代碼 會被丟棄和更換,但總體規模來說,Linux的內核在不斷增強,…

Python之路【第八篇】:堡壘機實例以及數據庫操作

Python之路【第八篇】&#xff1a;堡壘機實例以及數據庫操作 堡壘機前戲 開發堡壘機之前&#xff0c;先來學習Python的paramiko模塊&#xff0c;該模塊機遇SSH用于連接遠程服務器并執行相關操作 SSHClient 用于連接遠程服務器并執行基本命令 基于用戶名密碼連接&#xff1a; 12…

關于typedef的使用方法

在計算機編程語言中用來為復雜的聲明定義簡單的別名。與宏定義有些差異。它本身是一種存儲類的keyword&#xff0c;與auto、extern、mutable、static、register等keyword不能出如今同一個表達式中。typedef聲明&#xff0c;簡稱typedef&#xff0c;為現有類型創建一個新的名字&…

ADF BC:創建綁定到業務組件的UI表

在此示例中&#xff0c;我們將展示如何創建綁定到業務組件的簡單UI表&#xff08;af&#xff1a;table&#xff09;。 我再次嘗試使用簡單的標準在網上進行搜索&#xff1a; “如何創建綁定到業務組件ADF 11g的af&#xff1a;table” 我必須承認我沒有得到我想要的答案。 信息…

linux驅動程序混合架構,嵌入式系統最小驅動框架(類似linux驅動程序架構)(示例代碼)...

2010年就打算把linux里的驅動框架核心代碼摳出來的&#xff0c;但是由于懶而且linux代碼量大&#xff0c;一直下不了手。最近調試的intel curie里驅動架構也類似linux&#xff0c;代碼就少多了&#xff0c;由于工作需要不得不梳理一下這一堆代碼&#xff0c;今天花了一下午&…

MyBaits 錯誤分析

錯誤原因&#xff1a;在DAO的映射文件中&#xff0c;在映射標簽中的type類型寫成DAO類了&#xff0c;應該寫成javaBean轉載于:https://www.cnblogs.com/shuaiandjun/p/5428847.html

超越JUnit –測試框架的替代方案

JUnit是事實上的Java單元測試框架&#xff0c;但是可能有一些新的&#xff08;不是那么新的&#xff09;框架可以用于Web開發。 在采用之前可能要問自己的問題&#xff1a; 它們是否快速&#xff0c;容易開發&#xff0c;因此成本低廉&#xff1f; 他們運行快并因此鼓勵采用嗎…

tensorflow mnist read_data_sets fails

下載處理mnist數據時出現如下錯誤 VisibleDeprecationWarning: converting an array with ndim > 0 to an index will result in an error in the future 解決方法&#xff1a; 在input_data.py文件中return numpy.frombuffer(bytestream.read(4), dtypedt) 后添加[0] retur…

斑馬打印機linux驅動安裝教程,linux-Zebra軟件包的基本安裝與配置

Zebra是一個路由軟件包&#xff0c;提供基于TCP/IP路由服務&#xff0c;支持RIPv1, RIPv2, RIPng, OSPFv2, OSPFv3, BGP- 4,和 BGP-4等眾多路由協議。Zebra還支持BGP特性路由反射器(Route Reflector)。除了傳統的 IPv4路由協議&#xff0c;Zebra也支持IPv6路由協議。如果運行的…

iOS 改變App狀態欄顏色為白色

默認狀態欄為黑色&#xff0c;對于某些App不是很美觀&#xff0c;變成白色很簡單&#xff0c;只需要兩個步驟。 1.在Info.plist中添加新項目&#xff0c;View controller-based status bar appearance&#xff0c;Boolean值為No. 2.在AppDelegate的- (BOOL)application:(UIAppl…

Java 7對抑制異常的支持

在JDK 7中 &#xff0c;向Throwable類&#xff08; Exception和Error類的父類&#xff09;添加了一個新的構造函數和兩個新方法。 添加了新的構造函數和兩個新方法以支持“抑制的異常”&#xff08;不要與吞咽或忽略異常的不良做法相混淆&#xff09;。 在本文中&#xff0c;我…

linux 如何做共享磁盤陣列,在Linux上玩轉磁盤陣列分享

大部分用戶都會擔心&#xff0c;萬一硬盤發生故障&#xff0c;一、使用磁盤陣列可以帶來哪些好處?在具體如何配置磁盤陣列之前&#xff0c;筆者要先給大家介紹一下利用磁盤陣列的好處。先給大家一點動力&#xff0c;讓大家能夠繼續看下面的內容。第一個好處是磁盤陣列可以提高…

my-innodb-heavy-4g.cnf

my-innodb-heavy-4g.cnf轉載于:https://www.cnblogs.com/xiluhua/p/6231834.html

易于使用的單位和集成代碼

此示例說明如何使用Maven和Sonar生成單元測試和集成測試的覆蓋率。 它使用非常簡單的技術&#xff0c;只需10-15分鐘即可在任何現有的Maven構建中運行。 它可用于單元&#xff0c;集成&#xff0c;ATDD或任何其他類型的測試套件。 覆蓋率結果顯示在Sonar中。 有什么事嗎&#x…

Dij的堆優化

#include<algorithm> #include<iostream> #include<cstdio> #include<cstring> #include<queue> #define M 100000 #define pa pair<int,int>//優先比較第一個元素 using namespace std; int d[M],n,m,cnt,head[M],next[M],u[M],dis[M],n…

linux db2sysc 內存,db2sysc進程占用linux內存持續增長,請各位指點。

該服務器近期做過的變更情況&#xff1a;變更前&#xff0c;使用 sar -r 1 3 看內存使用率服務器內存使用率一直是70%該服務器原為獨立物理服務器&#xff0c;經過虛擬化遷移到EXS上成為虛擬服務器。遷移后發現swap無法啟動。原因是原物理服務器硬盤控制器為cciss。/etc/fstab …

k8s的探針

一、探針原理 分布式系統和微服務體系結構的挑戰之一是自動檢測不正常的應用程序&#xff0c;并將請求&#xff08;request&#xff09;重新路由到其他可用系統&#xff0c;恢復損壞的組件。健康檢查是應對該挑戰的一種可靠方法。使用 Kubernetes&#xff0c;可以通過探針配置運…