帳密。
圖形驗證碼的製作以 Java 2D 為基礎,透過 Servlet 動態產生驗證碼。
這邊作法有兩種,一種是已經事先產生好大量的驗證碼再去隨機取一張,另一種是如上述的方法
動態產生一張圖形驗證碼,這樣是比較安全的狀況,如果把驗證的圖放在某目錄下又沒加以保護
很容易讓人直接以URL取得你的所有圖檔,
以 Xuite 為例就是如此,在我這製作專題的過程中就是碰到類似問題幸好.....Xuite 不是動態產生,不然專題早掛摟....
首先先配置一個 Servlet 吧,以下為 SignalPage.java
package fsc.regLogIdent.controller; import com.sun.image.codec.jpeg.JPEGCodec; import com.sun.image.codec.jpeg.JPEGImageEncoder; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.geom.AffineTransform; import java.awt.geom.Line2D; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.Random; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; public class SignalPage extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpSession session = request.getSession(); response.setContentType("image/jpeg"); //設定回應的型態為 image/jpeg int width = 86; //圖形的寬度 int height = 25; //圖形的高度 Random random = new Random(); BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); //建立圖像 Graphics g = image.getGraphics(); Graphics2D g2d = (Graphics2D)g; Font f = new Font("黑體", Font.BOLD, 17); //設定字型的屬性 g.setColor(Color.LIGHT_GRAY); //圖像背景為亮灰色 g.fillRect(0, 0, width, height); //將背景繪上 g.setFont(f); //設定字型 g.setColor(Color.BLACK); //再將背景設定為黑色 //以下的迴圈會產生 100 條的干擾線 for(int i=0;i<100;i++) { //產生兩組作標 int x1 = random.nextInt(width-1); int y1 = random.nextInt(height-1); int x2 = random.nextInt(6) + 1; int y2 = random.nextInt(12) + 1; //建立干擾線的輪廓 bsk BasicStroke bsk = new BasicStroke(2f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL); Line2D line = new Line2D.Double(x1, y1, x1+x2, y1+y2); g2d.setStroke(bsk); g2d.draw(line); } String code = ""; //驗證碼 for(int i=0;i<4;i++) //產生四個隨機的英文或是數字 { switch(random.nextInt(2)) { case 0: //英文字母 int r = random.nextInt(26) + 65; code = code + String.valueOf((char)r); break; case 1: //數字 int n = random.nextInt(10) + 48; code = code + String.valueOf((char)n); } g.setColor(Color.YELLOW); //設定字型顏色 Graphics2D g2dAT = (Graphics2D)g; AffineTransform tran = new AffineTransform(); tran.scale(1.1, 1.3); //縮放 tran.rotate(random.nextInt(10)*3.14/180, 28, 14); //旋轉 g2dAT.setTransform(tran); g.drawString(code, 18, 14); //將驗證碼繪上 } session.setAttribute("code", code); //附加到 session 屬性中, 以便後續驗證所需 g.dispose(); //這裡要用 ServletOutputStream, 不要用 OutputStream ServletOutputStream os = response.getOutputStream(); JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(os); encoder.encode(image); } }
接下來看一下網頁吧 這邊只截取關鍵部份 SignalPage.jsp
<div style="padding-top: 5px;">
Identify : <input id="inputCode" type="text" size="5" onClick="showCode()" onkeyup="checkCode()" onmousemove="checkCode()" /> , Please click here for geting the Identify code.<br />
<input id="send" type="submit" value="Send" disabled="true" />
<p id="errorMsg" style="visibility: hidden;"></p>
</div>
<div id="show"></div>
需要使用者對輸入驗證碼的欄位點擊才會產生驗證碼所以以下的 div 初始值是 hidden
針對欄位的處理 當使用者放開任何案件或是滑鼠移動時
會用AJAX的方法檢查驗證碼是否正確
<div id="code" style="visibility: hidden;position: absolute;margin-left: 400px; width: 100px;" align="right">
<img id="identifyIMG" src="http://localhost:8084/regLogIdent/SignalPage" />
<a href="#" onClick="reloadIdentify()">換一個</a>
</div>
以上圖片的 src 就直接呼叫動態 Servlet 以產生圖形,接下來如果使用者看不清楚呢?
那就換一個吧,點擊 a link 會呼叫 javascript 的 reloadIdentify function
function reloadIdentify()
{
document.getElementById('inputCode').value = ""; //將輸入欄位清空
document.getElementById('inputCode').focus();
document.getElementById('identifyIMG').src = document.getElementById('identifyIMG').src + "?reload=" + new Date().getTime(); //重新設定 src
}
接下來用 AJAX 去驗證使用者輸入的驗證法是否正確 checkCode function
function checkCode()
{
if((document.getElementById('inputCode').value).toString().length >= 4){
var myXmlHttp = new XMLHttpRequest();
myXmlHttp.overrideMimeType("text/html");
var code = (document.getElementById('inputCode').value).toString();
myXmlHttp.onreadystatechange = function(){
if(myXmlHttp.readyState == 4){
if(myXmlHttp.state == 200){}
else{
if(myXmlHttp.responseText != 1){ // 不等於 1 代表驗證碼輸入錯誤
document.getElementById('errorMsg').innerHTML = myXmlHttp.responseText;
}else{
//隱藏錯誤訊息
document.getElementById('errorMsg').style.valueOf().visibility = "hidden";
//移除 submit 的 disable
document.getElementById('send').removeAttribute('disabled');
}
}
}
}
//checkCode 參數為使用者輸入的驗證碼 method 參數 為要使用的服務, 1 代表要效正驗證碼
myXmlHttp.open('GET', 'http://localhost:8084/regLogIdent/checkIndentify.jsp?checkCode=' + code + '&method=1', true);
myXmlHttp.send(null);
}else{ //如果驗證碼長度小於四, 則顯示說長度小於四
if(document.getElementById('errorMsg').style.valueOf().visibility == "visible"){
document.getElementById('errorMsg').innerHTML = "The code is too short";
}
}
}
以上的 AJAX 會呼叫 http://localhost:8084/regLogIdent/checkIndentify.jsp 並夾帶兩個參數
此JSP純粹只是用來驗證驗證碼或是一些其他的動作,以下為該JSP 的程式
<%
response.setContentType("text/html");
if(request.getParameter("method").equals("1")){ //method 為 1 代表要驗證驗證碼
if(request.getParameter("checkCode") != null){ //從 session 屬性取出 servlet 產生的驗證碼
if(request.getParameter("checkCode").equals(session.getAttribute("code"))){
out.println("1"); //成功驗證
}else{
out.println("error code !!"); //失敗
}
}else{
out.println("Invaild Way !!");
}
}else if(request.getParameter("method").equals("2")){
//其他服務動作
}
%>
沒有留言:
張貼留言