在网页编程中,经常需要使用到附加码这样的一个东西,防止黑客用程序用穷举法去破解密码。下面是我的一个附加码的Servlet实现。
1import java.awt.*;
2import java.awt.image.*;
3import java.io.*;
4import java.util.Random;
5import javax.servlet.*;
6import javax.servlet.http.*;
7
8import com.sun.image.codec.jpeg.*;
9
10public class KeyImage extends HttpServlet {
11
12 private static final String CONTENT_TYPE = "text/html; charset=GBK";
13
14 //Initialize global variables
15 public void init() throws ServletException {
16
17 }
18
19 /**//**
20 * 随机数生成器
21 */
22 private static Random random = new Random();
23
24 /**//**
25 * 系统所有的字符
26 */
27 private static Font[] fonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
28
29 /**//**
30 * 排除的一些字体(这些字体会显示不正常)
31 */
32 private static java.util.Set excludeFonts = new java.util.HashSet();
33
34 static {
35 excludeFonts.add("Cursor");
36 excludeFonts.add("Marlett");
37 excludeFonts.add("Symbol");
38 excludeFonts.add("Webdings");
39 excludeFonts.add("Wingdings");
40 excludeFonts.add("Wingdings 2");
41 }
42
43 /**//**
44 * 图片的宽度
45 */
46 private static int imageWidth = 90;
47
48 /**//**
49 * 图片的高度
50 */
51 private static int imageHeight = 30;
52
53 /**//**
54 * 背景颜色
55 */
56 private static Color backgroundColor = Color.WHITE;
57
58 /**//**
59 * 输出的字符数
60 */
61 private static int characterNumber = 4;
62
63 /**//**
64 * 最终附加码的字符串
65 */
66 private StringBuffer keyBuf = null;
67
68 /**//**
69 * 字符的颜色数组
70 */
71 private static Color[] colors = new Color[]{Color.BLACK, Color.BLUE,
72 Color.CYAN, Color.DARK_GRAY, Color.GRAY, Color.GREEN, Color.MAGENTA,
73 Color.RED};
74
75 /**//**
76 * 获得随机的X值(范围在5到9之间变化)
77 * @return int
78 */
79 private int randomX() {
80 return random.nextInt(5) + 5;
81 }
82
83 /**//**
84 * 获得随机的Y值(范围在20到24之间变化)
85 * @return int
86 */
87 private int randomY() {
88 return random.nextInt(5) + 20;
89 }
90
91 /**//**
92 * 随机产生字符的大小
93 * @return int 随机字符大小
94 */
95 private int randomSize() {
96 return random.nextInt(5) + 20;
97 }
98
99 /**//**
100 * 随机产生Font实例
101 * @return Font 随机Font实例
102 */
103 private Font randomFont() {
104 Font font = null;
105
106 if (fonts != null) {
107 font = fonts[random.nextInt(fonts.length)];
108 font = font.deriveFont(random.nextInt(3), randomSize());
109 } else {
110 font = new Font("Arial Black", Font.PLAIN, 15);
111 }
112
113 while (excludeFonts.contains(font.getName())) {
114 if (fonts != null) {
115 font = fonts[random.nextInt(fonts.length)];
116 font = font.deriveFont(random.nextInt(3), randomSize());
117 } else {
118 font = new Font("Arial Black", Font.PLAIN, 15);
119 }
120 }
121
122 log("Current Font: " + font.getName() + " Family: " + font.getFamily() + " Font Name: " + font.getFontName());
123
124 return font;
125 }
126
127 /**//**
128 * 随机生成一个Color实例(除了背景)
129 * @return Color 随机Color实例
130 */
131 private Color randomColor() {
132 int index = random.nextInt(colors.length);
133 log("Color index is: " + index);
134
135 return colors[index];
136 }
137
138 /**//**
139 * 写入一个字符
140 * @param g Graphics
141 * @param x int
142 * @param y int
143 */
144 private void drawCharacter(Graphics g, int x, int y) {
145 int ri = (int) (Math.random() * 10); // 随机生成的数字
146 keyBuf.append(ri);
147 g.setColor(randomColor());
148 g.setFont(randomFont());
149 g.drawString(String.valueOf(ri), x, y);
150 }
151
152 /**//**
153 * 绘制背景
154 * @param g Graphics
155 * @param color Color
156 * @param x int
157 * @param y int
158 * @param width int
159 * @param height int
160 */
161 private void drawBackground(Graphics g, Color color, int x, int y, int width,
162 int height) {
163 g.setColor(color);
164 g.fillRect(x, y, width, height);
165 }
166
167 /**//**
168 * 绘制干扰点,干扰线
169 * @param g Graphics
170 * @param width int
171 * @param height int
172 */
173 private void drawInterrupt(Graphics g, int width, int height) {
174 int numbers = random.nextInt(100) + 50; // 50到149个干扰点
175 g.setColor(Color.BLACK);
176
177 for (int i = 0; i < numbers; i++) {
178 g.fillRect(random.nextInt(width), random.nextInt(height), 1, 1);
179 }
180
181 g.drawLine(0, random.nextInt(height), width, random.nextInt(height));
182 }
183
184 /**//**
185 * Process the HTTP Get request
186 * 随机生成数字的策略:
187 * 1.随机渐变色(包括文字和背景,暂时不实现)
188 * 2.所有可打印字符(这里暂时用数字)
189 * 3.字符大小随机变化
190 * 4.位置不固定
191 * 5.象素行或列随机错位
192 * @param request HttpServletRequest
193 * @param response HttpServletResponse
194 * @throws ServletException
195 * @throws IOException
196 */
197 public void doGet(HttpServletRequest request, HttpServletResponse response)
198 throws ServletException, IOException {
199
200 BufferedImage image = new BufferedImage(imageWidth, imageHeight,
201 BufferedImage.TYPE_INT_RGB);
202 Graphics g = image.getGraphics();
203
204 drawBackground(g, backgroundColor, 0, 0, imageWidth, imageHeight);
205
206 keyBuf = new StringBuffer();
207 int offset = 0; // 偏移量
208 for (int i = 0; i < characterNumber; i++) {
209 drawCharacter(g, randomX() + offset, randomY());
210 offset += imageWidth / characterNumber;
211 }
212
213 drawInterrupt(g, imageWidth, imageHeight);
214
215 response.setHeader("Cache-Control", "no-store");
216 response.setDateHeader("Expires", 0);
217 response.setContentType("image/jpeg");
218
219 ServletOutputStream out = response.getOutputStream();
220
221 JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
222 encoder.encode(image);
223 out.close();
224
225 // 保存附加码
226 request.getSession().setAttribute("_key", keyBuf.toString());
227 log("The addtional code is: " + keyBuf.toString());
228 }
229
230 //Clean up resources
231 public void destroy() {
232 }
233
234 /**//**
235 * 改写服务器日志的输出
236 * @param msg String 要输出的信息
237 */
238 public void log(String msg) {
239 super.log(msg);
240 }
241
242 /**//**
243 * 改写服务器日志的输出
244 * @param message String 要输出的信息
245 * @param t Throwable 抛出的意外
246 */
247 public void log(String message, Throwable t) {
248 t.printStackTrace(System.out);
249 super.log(message, t);
250 }
251} 附加码的效果图:
posted on 2005-05-12 15:33
小米 阅读(1408)
评论(4) 编辑 收藏 所属分类:
Java