10.6.3 处理用户登录

10.6.3 处理用户登录

该系统有一些功能只有登录用户才能使用。如果用户单击页面上方的”登录”链接,链接上的事件处理函数将会在目标页面上装载login.html页面,该页面的内容主要是一个表单—该页面不需要有完整的页面内容,只要有表单部分即可。下面是该页面的代码。
程序清单:codes\10\auction\WebContent\login.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<script src="js/login.js"></script>
<div class="container">
<!-- 登录界面 -->
<div class="page-header">
<h1>用户登录</h1>
</div>
<form class="form-horizontal" method="post">
<!-- .form-group相当于.row对应响应式布局的一行 -->
<div class="form-group">
<div class="col-sm-6">
<input class="form-control" placeholder="用户名/邮箱"
type="text" id="loginUser" name="loginUser" required
minlength="3" maxlength="10" />
</div>
</div>
<div class="form-group">
<div class="col-sm-6">
<input class="form-control" placeholder="密码"
id="loginPass" type="password" name="loginPass"
required minlength="3" maxlength="10" />
</div>
</div>
<div class="form-group">
<div class="col-sm-6">
<div class="input-group">
<input class="form-control " id="vercode"
name="vercode" type="text" placeholder="验证码"
required pattern="\w{6}"> <span
class="input-group-addon" id="basic-addon2">
验证码:<img src="auth.jpg" name="d" id="d"
alt="验证码" />
</span>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-6">
<div class="btn-group btn-group-justified" role="group"
aria-label="...">
<div class="btn-group" role="group">
<button type="submit" id="loginBtn"
class="btn btn-success">
<span class="glyphicon glyphicon-log-in"></span>&nbsp;登录
</button>
</div>
</div>
</div>
</div>
</form>
</div>

这个页面就是一个简单的表单,当用户单击页面上的”登录”按钮时,系统会触发登录处理。登录处理由页面上加载的login.js负责。浏览该页面可以看到如图10.11所示的登录界面。

由图10.11可看到,系统登录使用了一个随机图形验证码。使用随机图形验证码是为了增加系统安全性,防止Cracker暴力破解。该图形验证码实质上就是一个Servlet,与普通的Servlet不同的是,该Servlet不生成文本内容,而是生成图形内容,其代码如下。
程序清单:codes\10\auction\src\org\crazyit\auction\web\AuthImg.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package org.crazyit.auction.web;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

@WebServlet(urlPatterns ={"/auth.jpg"})
public class AuthImg extends HttpServlet
{
private static final long serialVersionUID = 1L;
// 定义图形验证码中绘制字符的字体
private final Font mFont = new Font("Arial Black", Font.PLAIN, 16);
// 定义图形验证码的大小
private final int IMG_WIDTH = 100;
private final int IMG_HEIGTH = 18;
// 定义一个获取随机颜色的方法
private Color getRandColor(int fc, int bc)
{
Random random = new Random();
if (fc > 255)
fc = 255;
if (bc > 255)
bc = 255;
int r = fc + random.nextInt(bc - fc);
int g = fc + random.nextInt(bc - fc);
int b = fc + random.nextInt(bc - fc);
// 得到随机颜色
return new Color(r, g, b);
}
// 重写service方法,生成对客户端的响应
public void service(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException
{
// 设置禁止缓存
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
response.setContentType("image/jpeg");
BufferedImage image = new BufferedImage(IMG_WIDTH, IMG_HEIGTH,
BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
Random random = new Random();
g.setColor(getRandColor(200, 250));
// 填充背景色
g.fillRect(1, 1, IMG_WIDTH - 1, IMG_HEIGTH - 1);
// 为图形验证码绘制边框
g.setColor(new Color(102, 102, 102));
g.drawRect(0, 0, IMG_WIDTH - 1, IMG_HEIGTH - 1);
g.setColor(getRandColor(160, 200));
// 生成随机干扰线
for (int i = 0; i < 80; i++)
{
int x = random.nextInt(IMG_WIDTH - 1);
int y = random.nextInt(IMG_HEIGTH - 1);
int xl = random.nextInt(6) + 1;
int yl = random.nextInt(12) + 1;
g.drawLine(x, y, x + xl, y + yl);
}
g.setColor(getRandColor(160, 200));
// 生成随机干扰线
for (int i = 0; i < 80; i++)
{
int x = random.nextInt(IMG_WIDTH - 1);
int y = random.nextInt(IMG_HEIGTH - 1);
int xl = random.nextInt(12) + 1;
int yl = random.nextInt(6) + 1;
g.drawLine(x, y, x - xl, y - yl);
}
// 设置绘制字符的字体
g.setFont(mFont);
// 用于保存系统生成的随机字符串
String sRand = "";
for (int i = 0; i < 6; i++)
{
String tmp = getRandomChar();
sRand += tmp;
// 获取随机颜色
g.setColor(new Color(20 + random.nextInt(110),
20 + random.nextInt(110), 20 + random.nextInt(110)));
// 在图片上绘制系统生成的随机字符
g.drawString(tmp, 15 * i + 10, 15);
}
// 获取HttpSesssion对象
HttpSession session = request.getSession(true);
// 将随机字符串放入HttpSesssion对象中
session.setAttribute("rand", sRand);
g.dispose();
// 向输出流中输出图片
ImageIO.write(image, "JPEG", response.getOutputStream());
}
// 定义获取随机字符串方法
private String getRandomChar()
{
// 生成一个0、1、2的随机数字
int rand = (int) Math.round(Math.random() * 2);
long itmp = 0;
char ctmp = '\u0000';
switch (rand)
{
// 生成大写字母
case 1 :
itmp = Math.round(Math.random() * 25 + 65);
ctmp = (char) itmp;
return String.valueOf(ctmp);
// 生成小写字母
case 2 :
itmp = Math.round(Math.random() * 25 + 97);
ctmp = (char) itmp;
return String.valueOf(ctmp);
// 生成数字
default :
itmp = Math.round(Math.random() * 9);
return itmp + "";
}
}
}

编写完该Servlet后,使用Annotation将它的URL映射为/auth.jsp,这样即可在HTML页面中通过如下方式显示图形验证码:

1
<img name="d" src="auth.jsp" alt="验证码"/>

使用图形验证码与使用普通图片并没有太大的区别,唯一的区别是将原来指定普通图片的src属性改为指定图形验证码ServletURL
处理用户登录的login.js代码如下。
程序清单:codes\10\auction\WebContent\js\login.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// 定义登录的JS
// 文档加载完成以后进行异步登录
$(function () {
// 取消对话框中两个按钮上绑定的事件处理函数
$("#sure").unbind("click");
$("#cancelBn").unbind("click");
$(".form-horizontal").submit(function () {
// 发起异步登录
$.post("auction/loginAjax", $(".form-horizontal").serializeArray()
, function (data) {
if (data.error) {
$("#tip").html("<span style='color:red;'>" + data.error + "</span>");
$('#myModal').modal('show');
return;
}
switch (data) {
case '-2': // 验证码不正确
$("#tip").html("<span style='color:red;'>您输入的验证码不正确,请重新输入</span>");
$("#vercode").val('');
break;
case '-1': // 用户名、密码不正确
$("#tip").html("<span style='color:red;'>您输入的用户名、密码不正确,请重新输入</span>");
$(".form-horizontal").get(0).reset(); // 重设表单
break;
case '1': // 用户名、密码正确
$("#tip").html("<span style='color:red;'>登录成功,您可以继续使用系统了</span>");
// 为对话框中的"确定"按钮绑定单击事件处理函数
$("#sure").click(function () {
goPage("home.html");
})
break;
}
// 显示对话框
$('#myModal').modal('show');
});
return false;
})
})

在代码的开始部分取消了对话框中两个按钮上绑定的事件处理函数,接下来粗体字代码使用jQuerypost()方法向auction/loginAjax提交异步请求,随后可处理用户的登录请求。