驗證碼?
就是防止機器人送出表單的驗證圖片,這是目前辨識真假人最常見的作法。驗證流程
- 使用 <img src="..."/> 產生驗證圖片,注意 src 是指向 Java Servlet,用以動態產生驗驗證圖片,而不是一張靜態的圖片。
- 在 web.xml 設定產生驗證圖片的 <servlet/> 與 <servlet-mapping/>
- 撰寫 Java Servlet,每次呼叫 Java Servlet 時,除產生驗證圖片塞到 response 以外,還要將答案寫到 session 裡,供事後比對。
- Form submit 到後台時,左手拿使用者輸入的驗證碼,右手拿 session 裡的答案,兩相做比較即可。
貼心的功能
- 在網頁上加上「重新產生驗證碼」功能,只要使用 Javascript 讓 img 重新載入圖片就可以,若擔心 cache,可以每次重新整理時在網址上加上時間戳記。
- 在網頁輸入時,使用 Javascript 將輸入的值自動轉大寫,當然驗證值一開始就得是大寫,這可以減低傷害使用者的耐心。
- 送到後台比對時,先將兩邊(使用者輸入與從 session 取得的答案)值的英文字母「歐」都換成數字「零」,以及英文字母「唉」換成數字「壹」,這是避免 O / 0 與 I / 1 的誤會。
下載 SimpleCaptcha
請到官網下載,目前版本是 1.2.1,Maven repository 上的還是 1.1.1,Maven Repository 上還有個版本超前官網的 1.2.2 的同名 library,別誤會了,這可是強國人製作的,原因不明。
然後在 web.xml 加上以下設定,重起湯姆貓,就可以在 http://localhost/stickyImg 看到驗證圖片了,重新整理也可以看到每次驗證碼都不同。
然後在 web.xml 加上以下設定,重起湯姆貓,就可以在 http://localhost/stickyImg 看到驗證圖片了,重新整理也可以看到每次驗證碼都不同。
<servlet> <servlet-name>StickyCaptcha</servlet-name> <servlet-class>nl.captcha.servlet.StickyCaptchaServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>StickyCaptcha</servlet-name> <url-pattern>/stickyImg</url-pattern> </servlet-mapping>很簡單?但是預設的文字/圖片真的有點不美觀。
客制 SimpleCaptcha
就是改寫 nl.captcha.servlet.SimpleCaptchaServlet,客制文字字型與大小,以及背景圖。public class EasySimpleCaptchaServlet extends SimpleCaptchaServlet {
// 以下四個參數相互影響,圖大則字型大,字多字大則圖大
private int width = 60;
private int height = 25;
private int length = 4;
private int fontSize = 20;
// 背景圖,放在 classpath 裡
private String backgroundImg = "CaptchaBackground.jpg";
@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 建立 Captcha 物件
Captcha captcha = this.buildCaptcha();
// 將 Captcha 物件裡的圖片寫入 HttpServletResponse
CaptchaServletUtil.writeImage(resp, captcha.getImage());
// form submit 後再用 Captcha.NAME 取得 Captcha 物件,然後呼叫 getAnswer() 來比值
req.getSession().setAttribute(Captcha.NAME, captcha);
}
private Captcha buildCaptcha() {
// 文字顏色
List<Color> colorList = new ArrayList<Color>();
colorList.add(Color.BLACK);
// 文字字型
List<Font> fontList = new ArrayList<Font>();
fontList.add(new Font(Font.SERIF, Font.BOLD, this.fontSize));
// 設定長寬、設定文字產生器、設定文字顏色與字型、設定背景
Captcha captcha = new Captcha.Builder(this.width, this.height).addText(new EasyTextProducer(this.length),
new DefaultWordRenderer(colorList, fontList)).addBackground(new EasyBackgroundProducer()).build();
return captcha;
}
/**
* 設定背景 - 以一張圖片作為背景,並隨機使用背景圖片的某一位置
*/
private final class EasyBackgroundProducer implements BackgroundProducer {
/**
* 不知道作用,不用改
*/
@Override
public BufferedImage addBackground(BufferedImage bi) {
int width = bi.getWidth();
int height = bi.getHeight();
return this.getBackground(width, height);
}
@Override
public BufferedImage getBackground(int width, int height) {
try {
// 讀入背景圖
Image image = ImageIO.read(this.getClass().getClassLoader().getResourceAsStream(backgroundImg));
BufferedImage buffered = (BufferedImage) image;
// 可用的 x 與 y 值
int x = buffered.getWidth() - width;
int y = buffered.getHeight() - height;
// 隨機產生
x = (int) (Math.random() * x);
y = (int) (Math.random() * y);
// 防呆
x = Math.max(x, 0);
y = Math.max(y, 0);
// 切出需要的背景圖
return buffered.getSubimage(x, y, width, height);
}
catch (IOException e) {
e.printStackTrace();
}
// 若出意外,挺多沒有背景圖
return null;
}
}
/**
* 文字產生器 - 只使用 數字與大寫英文字母
*/
private final class EasyTextProducer implements TextProducer {
private int length;
public EasyTextProducer(int length) {
// 設定驗證碼長度
this.length = length;
}
@Override
public String getText() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < this.length; i++) {
int n = (int) (Math.random() * 36);
if (n <= 9) {
sb.append(String.valueOf(n));
}
else {
n -= 10;
n += 97;
sb.append((char) n);
}
}
return sb.toString().toUpperCase();
}
}
public static void main(String[] args) throws IOException {
Captcha captcha = new EasySimpleCaptchaServlet().buildCaptcha();
File outputfile = new File("image_" + new Date().getTime() + ".jpg");
ImageIO.write(captcha.getImage(), "jpg", outputfile);
}
}
不解釋,看起來好多了。// 重新產生驗證圖片
$('#stickyImg').attr('src', 'stickyImg?_v=' + new Date().getTime());
// 自動轉大寫
$('input[name=verifyCode]').keyup(function(){
$(this).val($(this).val().toUpperCase());
});
------
---



沒有留言:
張貼留言