Java Web開(kāi)發(fā)過(guò)程中登陸模塊的驗(yàn)證碼的實(shí)現(xiàn)方式總結(jié)
驗(yàn)證碼及它的作用
驗(yàn)證碼為全自動(dòng)區(qū)分計(jì)算機(jī)和人類(lèi)的圖靈測(cè)試的縮寫(xiě),是一種區(qū)分用戶是計(jì)算機(jī)的公共全自動(dòng)程序,這個(gè)問(wèn)題可以由計(jì)算機(jī)生成并評(píng)判,但是必須只有人類(lèi)才能解答.可以防止惡意破解密碼、刷票、論壇灌水、有效防止某個(gè)黑客對(duì)某一個(gè)特定注冊(cè)用戶用特定程序暴力破解方式進(jìn)行不斷的登錄。
圖文驗(yàn)證碼的原理
在servlet中隨機(jī)生成一個(gè)指定位置的驗(yàn)證碼,一般為四位,然后把該驗(yàn)證碼保存到session中.在通過(guò)Java的繪圖類(lèi)以圖片的形式輸出該驗(yàn)證碼。為了增加驗(yàn)證碼的安全級(jí)別,可以輸出圖片的同時(shí)輸出干擾線,最后在用戶提交數(shù)據(jù)的時(shí)候,在服務(wù)器端將用戶提交的驗(yàn)證碼和Session保存的驗(yàn)證碼進(jìn)行比較。
實(shí)現(xiàn)方式總結(jié)
1 驗(yàn)證碼生成類(lèi)RandomCode
RandomCode是一個(gè)生成驗(yàn)證碼的工具類(lèi),支持英文和數(shù)字驗(yàn)證碼,驗(yàn)證碼包括英文大小寫(xiě)和數(shù)組,其中英文i、o和數(shù)字0、1因?yàn)槿菀桩a(chǎn)生混淆,不包括在生成驗(yàn)證碼中。RandomCode支持輸出jpg/bmp/png/gif圖片格式的驗(yàn)證碼。
/** * RandomCode驗(yàn)證碼可以通過(guò)靜態(tài)方法和實(shí)例方法生成。 * * 靜態(tài)方法: * * //生成長(zhǎng)度為4的隨機(jī)驗(yàn)證碼 * String code = RandomCode.randomString(4); * * //把驗(yàn)證碼圖片輸入到response輸出流中 * //圖片格式j(luò)pg * OutputStream os = response.getOutputStream(); * RandomCode.write(code, 120, 30, os, "jpg"); * * 實(shí)例方法: * * //實(shí)例化驗(yàn)證碼類(lèi) * RandomCode rc = new RandomCode(4); * * //把驗(yàn)證碼圖片輸入到response輸出流中 * //圖片格式j(luò)pg * OutputStream os = response.getOutputStream(); * rc.write(120, 30, os, "jpg"); * * //獲取驗(yàn)證碼字符串 * String code = rc.getCode(); * */ public class RandomCode { /** * 隨機(jī)驗(yàn)證碼字符 */ private static String base = "abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789"; /** * 隨機(jī)驗(yàn)證碼長(zhǎng)度 */ private int length = 4; /** * 驗(yàn)證碼字符串 */ private String code; /** * 4位隨機(jī)驗(yàn)證碼 */ public RandomCode(){ this.code = RandomCode.randomString(this.length); } public RandomCode(int length){ if(length > 0){ this.length = length; } this.code = RandomCode.randomString(this.length); } /** * 生成驗(yàn)證碼圖片 * @param width 圖片寬度 * @param height 圖片高度 * @return */ public BufferedImage toImage(int width, int height){ return RandomCode.toImage(this.code, width, height); } /** * 輸出驗(yàn)證碼圖片,默認(rèn)圖片格式j(luò)peg * @param width * @param height * @param os * @throws IOException */ public void write(int width, int height, OutputStream os) throws IOException{ RandomCode.write(code, width, height, os, "jpeg"); } /** * 輸出驗(yàn)證碼圖片 * @param width * @param height * @param os * @param format 圖片格式,支持jpg/jpeg/bmp/gif/png * @throws IOException */ public void write(int width, int height, OutputStream os, String format) throws IOException{ RandomCode.write(code, width, height, os, format); } public int getLength() { return length; } public String getCode() { return code; } /** * 靜態(tài)方法 * 生成隨機(jī)字符串 * @param length 字符串長(zhǎng)度 * @return 隨機(jī)字符串 */ public static String randomString(int length){ Random random = new Random(); StringBuffer sb = new StringBuffer(); for(int i = 0; i < length; i++){ sb.append(base.charAt(random.nextInt(base.length()))); } return sb.toString(); } /** * 靜態(tài)方法 * 輸出驗(yàn)證碼圖片 * @param code 驗(yàn)證碼字符串 * @param width 圖片寬度 * @param height 圖片高度 * @param os 圖片輸出流 * @param format 圖片格式,支持jpg/jpeg/bmp/gif/png * @throws IOException */ public static void write(String code, int width, int height, OutputStream os, String format) throws IOException{ BufferedImage image = toImage(code, width, height); ImageIO.write(image, format, os); } /** * 靜態(tài)方法 * 輸出驗(yàn)證碼圖片,默認(rèn)圖片格式j(luò)peg * @param code 驗(yàn)證碼字符串 * @param width 圖片寬度 * @param height 圖片高度 * @param os 圖片輸出流 * @throws IOException */ public static void write(String code, int width, int height, OutputStream os) throws IOException{ write(code, width, height, os, "jpeg"); } /** * 靜態(tài)方法 * 字符串轉(zhuǎn)成驗(yàn)證碼圖片 * @param code 驗(yàn)證碼字符串 * @param width 驗(yàn)證碼圖片寬度,單位像素 * @param height 驗(yàn)證碼圖片高度,單位像素 * @return */ public static BufferedImage toImage(String code, int width, int height){ //字體大小 int fontSize = (int)Math.ceil(height * 0.9); if(fontSize < 20){ fontSize = 20; } //字體在Y坐標(biāo)上的位置 int positionY = (int)Math.ceil(height * 0.8); int lenCode = code.length(); //計(jì)算字體寬度 int fontWidth = width / (lenCode + 2); BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR); Graphics g = image.getGraphics(); //圖片背景隨機(jī)顏色 g.setColor(randomColor(new Random(), 200, 250)); g.fillRect(0, 0, width, height); //設(shè)置字體 g.setFont(new Font("Times New Roman", Font.BOLD, fontSize)); //在圖片上畫(huà)縱橫交錯(cuò)的線,達(dá)到混淆效果 drawLines(g, width, height); //在圖片上畫(huà)驗(yàn)證碼 drawString(g, code, fontWidth, positionY); g.dispose(); return image; } /** * 靜態(tài)方法 * 在圖片上話位子 * @param g * @param code 驗(yàn)證碼字符串 * @param fontWidth 字體寬度 * @param positionY 字體Y坐標(biāo) */ private static void drawString(Graphics g, String code, int fontWidth, int positionY){ int len = code.length(); Random random = new Random(); for(int i = 0; i < len; i++){ g.setColor(randomColor(random)); g.drawString(String.valueOf(code.charAt(i)), (i + 1) * fontWidth, positionY); } } private static Color randomColor(Random random){ int r = random.nextInt(255); int g = random.nextInt(255); int b = random.nextInt(255); return new Color(r, g, b); } private static Color randomColor(Random random, int fc, int bc){ if(fc > 255){ fc = 255; } if(bc > 255){ bc = 255; } int diff = bc-fc; int r = fc + random.nextInt(diff); int g = fc + random.nextInt(diff); int b = fc + random.nextInt(diff); return new Color(r,g,b); } /** * 靜態(tài)方法 * 畫(huà)縱橫交錯(cuò)的線 * @param g * @param width 驗(yàn)證碼圖片寬度 * @param height 驗(yàn)證碼圖片高度 */ private static void drawLines(Graphics g, int width, int height){ Random random = new Random(); //線的數(shù)量 int count = ((int)(Math.ceil(random.nextDouble() * 100))) + 100; for(int i = 0; i < count; i++){ int fc = 160 + (int)Math.ceil(random.nextDouble() * 40); int bc = 200 + (int)Math.ceil(random.nextDouble() * 55); g.setColor(randomColor(random, fc, bc)); int x = random.nextInt(width); int y = random.nextInt(height); int xl = random.nextInt(width / 5); int yl = random.nextInt(height / 5); g.drawLine(x, y, x + xl, y + yl); } } }
2 Servlet返回驗(yàn)證碼
請(qǐng)求路徑http://<網(wǎng)站路徑>/random/code/servlet
@WebServlet("/random/code/servlet") public class RandomCodeServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 驗(yàn)證碼圖片寬度,單位像素 int width = 120; // 驗(yàn)證碼圖片高度,單位像素 int height = 30; // 驗(yàn)證碼圖片格式 String format = "png"; // 驗(yàn)證碼字符長(zhǎng)度 int len = 4; // 設(shè)置圖片格式 response.setContentType("image/" + format); // 禁止瀏覽器緩存圖片 response.setHeader("Pragma", "no-cache"); response.setHeader("Cache-Control", "no-cache"); response.setDateHeader("Expires", 0); String code = RandomCode.randomString(len); // 把圖片輸出到response輸出流 RandomCode.write(code, width, height, response.getOutputStream(), format); } }
3 Strust2返回驗(yàn)證碼
public class RandomCodeAction extends ActionSupport { private static final long serialVersionUID = -7515645222798283236L; /** * 獲取驗(yàn)證碼 */ public void generateCode() { HttpServletResponse response = ServletActionContext.getResponse(); // 驗(yàn)證碼圖片寬度,單位像素 int width = 120; // 驗(yàn)證碼圖片高度,單位像素 int height = 30; // 驗(yàn)證碼圖片格式 String format = "png"; // 驗(yàn)證碼字符長(zhǎng)度 int len = 4; // 設(shè)置圖片格式 response.setContentType("image/" + format); // 禁止瀏覽器緩存圖片 response.setHeader("Pragma", "no-cache"); response.setHeader("Cache-Control", "no-cache"); response.setDateHeader("Expires", 0); String code = RandomCode.randomString(len); // 把圖片輸出到response輸出流 try { RandomCode.write(code, width, height, response.getOutputStream(), format); } catch (IOException e) { e.printStackTrace(); } } }
Struts2的驗(yàn)證碼配置
<package name="pkg-random-code" namespace="/" extends="struts-default"> <action name="randomCode_*" method="{1}" class="com.rhui.web.action.RandomCodeAction"></action> </package>
請(qǐng)求路徑http://<網(wǎng)站路徑>/randomCode_generateCode.do
4 SpringMVC返回驗(yàn)證碼
請(qǐng)求路徑http://<網(wǎng)站路徑>/random/code/generate.do
package com.rhui.web.controller; import java.io.IOException; import javax.servlet.http.HttpServletResponse; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import com.rhui.util.RandomCode; @Controller @RequestMapping("/random/code") public class RandomCodeController { @RequestMapping("/generate.do") public void generateCode(HttpServletResponse response) { // 驗(yàn)證碼圖片寬度,單位像素 int width = 120; // 驗(yàn)證碼圖片高度,單位像素 int height = 30; // 驗(yàn)證碼圖片格式 String format = "png"; // 驗(yàn)證碼字符長(zhǎng)度 int len = 4; // 設(shè)置圖片格式 response.setContentType("image/" + format); // 禁止瀏覽器緩存圖片 response.setHeader("Pragma", "no-cache"); response.setHeader("Cache-Control", "no-cache"); response.setDateHeader("Expires", 0); String code = RandomCode.randomString(len); // 把圖片輸出到response輸出流 try { RandomCode.write(code, width, height, response.getOutputStream(), format); } catch (IOException e) { e.printStackTrace(); } } }
相關(guān)文章
peewee創(chuàng)建連接前的前置操作wireshark抓包實(shí)現(xiàn)
這篇文章主要為大家介紹了peewee創(chuàng)建連接前的前置操作wireshark?抓包實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10Python上下文管理器類(lèi)和上下文管理器裝飾器contextmanager用法實(shí)例分析
這篇文章主要介紹了Python上下文管理器類(lèi)和上下文管理器裝飾器contextmanager用法,結(jié)合實(shí)例形式分析了上下文管理器類(lèi)定義、使用、sqlalchemy實(shí)現(xiàn)數(shù)據(jù)庫(kù)的自動(dòng)提交和回滾相關(guān)操作技巧,需要的朋友可以參考下2019-11-11Python如何實(shí)現(xiàn)拆分?jǐn)?shù)據(jù)集
這篇文章主要介紹了Python如何實(shí)現(xiàn)拆分?jǐn)?shù)據(jù)集問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-09-09python實(shí)點(diǎn)云分割k-means(sklearn)詳解
這篇文章主要為大家詳細(xì)介紹了Python實(shí)點(diǎn)云分割k-means,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-05-05python中pandas.DataFrame排除特定行方法示例
這篇文章主要給大家介紹了關(guān)于python中pandas.DataFrame排除特定行的方法,文中給出了詳細(xì)的示例代碼,相信對(duì)大家的理解和學(xué)習(xí)具有一定的參考價(jià)值,需要的朋友們下面來(lái)一起看看吧。2017-03-03Pytorch中Softmax與LogSigmoid的對(duì)比分析
這篇文章主要介紹了Pytorch中Softmax與LogSigmoid的對(duì)比分析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06Python Web框架之Django框架cookie和session用法分析
這篇文章主要介紹了Python Web框架之Django框架cookie和session用法,結(jié)合實(shí)例形式分析了Django框架cookie和session的常見(jiàn)使用技巧與操作注意事項(xiàng),需要的朋友可以參考下2019-08-08