JA-SIG CAS - 3-1: 增加Captcha功能

有關jCaptch則是也是先選輕鬆把功能先搞出來的方法。因為信心缺乏症候群,所以先用簡單蠻幹的東西建立信心。信心建立以後在想其他問題。

Listing. cas-server-core pom.xml add jcaptcha dependency

192 <!-- jCaptcha -->
193 <DEPENDENCY>
194     <GROUPID>com.octo.captcha</GROUPID>
195     <ARTIFACTID>jcaptcha</ARTIFACTID>
196     <VERSION>1.0</VERSION>
197 </DEPENDENCY>

接著根據jcaptch網站『快快樂樂使用jCaptcha』的文章寫一個產生唯一default image captcha service instance的class和產生圖的servlet。程式都是抄jCaptcha網站滴。

Listing. CaptchaServiceSingleton.java

01 package org.jasig.cas.captcha;
02   
03 import com.octo.captcha.service.image.ImageCaptchaService;
04 import com.octo.captcha.service.image.DefaultManageableImageCaptchaService;
05   
06 public class CaptchaServiceSingleton {
07     private static ImageCaptchaService instance = new DefaultManageableImageCaptchaService();
08   
09     public static ImageCaptchaService getInstance() {
10         return instance;
11     }
12 }

Listing. ImageCaptchaServlet.java

01 package org.jasig.cas.captcha;
02   
03 import com.octo.captcha.service.CaptchaServiceException;
04 import com.sun.image.codec.jpeg.JPEGCodec;
05 import com.sun.image.codec.jpeg.JPEGImageEncoder;
06   
07 import javax.servlet.ServletConfig;
08 import javax.servlet.ServletException;
09 import javax.servlet.ServletOutputStream;
10 import javax.servlet.http.HttpServlet;
11 import javax.servlet.http.HttpServletRequest;
12 import javax.servlet.http.HttpServletResponse;
13 import java.awt.image.BufferedImage;
14 import java.io.ByteArrayOutputStream;
15 import java.io.IOException;
16   
17   
18 public class ImageCaptchaServlet extends HttpServlet {
19   
20   
21     public void init(ServletConfig servletConfig) throws ServletException {
22         super.init(servletConfig);
23     }
24   
25   
26     protected void doGet(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException {
27   
28        byte[] captchaChallengeAsJpeg = null;
29        // the output stream to render the captcha image as jpeg into
30         ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();
31         try {
32         // get the session id that will identify the generated captcha.
33         //the same id must be used to validate the response, the session id is a good candidate!
34         String captchaId = httpServletRequest.getSession().getId();
35         // call the ImageCaptchaService getChallenge method
36             BufferedImage challenge =
37                     CaptchaServiceSingleton.getInstance().getImageChallengeForID(captchaId,
38                             httpServletRequest.getLocale());
39   
40             // a jpeg encoder
41             JPEGImageEncoder jpegEncoder =
42                     JPEGCodec.createJPEGEncoder(jpegOutputStream);
43             jpegEncoder.encode(challenge);
44         } catch (IllegalArgumentException e) {
45             httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND);
46             return;
47         } catch (CaptchaServiceException e) {
48             httpServletResponse.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
49             return;
50         }
51   
52         captchaChallengeAsJpeg = jpegOutputStream.toByteArray();
53   
54         // flush it in the response
55         httpServletResponse.setHeader("Cache-Control", "no-store");
56         httpServletResponse.setHeader("Pragma", "no-cache");
57         httpServletResponse.setDateHeader("Expires", 0);
58         httpServletResponse.setContentType("image/jpeg");
59         ServletOutputStream responseOutputStream =
60                 httpServletResponse.getOutputStream();
61         responseOutputStream.write(captchaChallengeAsJpeg);
62         responseOutputStream.flush();
63         responseOutputStream.close();
64     }
65 }

在cas-server-webapp module裡面要使用captcha servlet就必須在web.xml設定servlet,另外在/WEB-INF/view/jsp/default/ui/casLogingView.jsp這個jsp就可以加上img element就可以看到captcha image。

AuthenticationViaFormAction Modification

蠻幹小胖的手腳是動在submit()這個method,根據jCaptch網站的資訊要使用validateReponseForID()要取得session id,正好在AuthenticationViaForm#doBind()可以看到CAS有寫一個WebUtil class可以從Spring WebFlow的RequestContext中取得HttpServletRequest物件。因此我們可以輕鬆拿來利用一下。

Listing. AuthenticationViaFormAction#submit() captcha validate 程式片段

66 final HttpServletRequest request = WebUtils.getHttpServletRequest(context);      // for captcha
67 Boolean isResponseCorrect = Boolean.FALSE;                                       // for captcha
68 String enterCaptchaId = request.getParameter( "j_captcha_response" );            // for captcha
69 String captchaId = request.getSession().getId();                                 // for captcha
70 // for captcha check input and expect value begin
71 try {
72     isResponseCorrect = CaptchaServiceSingleton.getInstance().validateResponseForID(captchaId, enterCaptchaId);
73 } catch (CaptchaServiceException e) {
74     //should not happen, may be thrown if the id is not valid
75 }
76 // for captcah input and expect value end

Listing. AuthenticationViaFormAction#submit() 增加流程的程式片段

097 if( Boolean.TRUE.equals(isResponseCorrect) ) {  // for captcha
098     WebUtils.putTicketGrantingTicketInRequestScope(context, this.centralAuthenticationService.createTicketGrantingTicket(credentials));
099     putWarnCookieIfRequestParameterPresent(context);
100     return "success";
101 } else {           // for captcha
102     // for captcha, captcha validate failed
103     return "warn"; // for captcha 
104 }                  // for captcha

posted on 2013-01-11 20:14  大雨2012快乐  阅读(294)  评论(0)    收藏  举报

导航