**CMS内容管理系统登录模块一共有以下几点内容
1.登录页面中对账号,密码,验证码进行正确性校验
2. 验证码的生成
3. 账号,密码,验证码的校验
4. 数据库连接,并取出用户数据
5. 使用过滤器,防止用户直接访问后台页面,增加安全性
**
1.登录页面的正确性校验
登录页面中账号密码的正确性校验需要对输入字符进行非空检验,长度校验,字符合法校验
<1>.非空校验
function isNotNull(name,c){
if(c == null || c.length <= 0){
alert(name + "字段不能为空!");
return false;
}
return true;
}
<2>.长度校验
function length(name,c,minlen,maxlen){ //参数,字段名,最少字符数,最多字符数
if(c.length < minlen || c.length > maxlen){
alert(name + "字段字符个数必须在" + minlen + "到" + maxlen + "个之间");
return false;
}
return true;
}
<3>.字符合法校验
function regulex(name,cc) { 参数,字段名,被检验的字符串
var a = /^.*[0-9]+.*$/;
var b = /^.*[a-z]+.*$/;
var c = /^.*[A-Z]+.*$/;
var d = /^.*[\*\&\^\%\!\$\~\(\)]+.*$/;
if(a.test(cc) && b.test(cc)&& c.test(cc)&&d.test(cc)){ //正则表达式检验是否含有指定字符
return true;
}
alert(name + "不符合规则!字段值必须包括数字大小写字母及符号" ); //如果错误,弹窗提醒错误
return false;
}
2.验证码生成
<1>.随机生成四个字符
随机生成字符,需要定义一个字符串code,将需要随机生成的字符内容包含进去,然后通过生成随机数,通过随机数定位在字符串中指定位置,取出该字符。随机生成的数字范围在0-code.length()之间,这样可以保证生成的随机数,在字符串中有与之相对应的字符。
生成随机数,定位字符串位置代码:
private String code = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
private char genericCheckCode(){
int count = code.length();
int randomIndex = new Random().nextInt(count);//得到随机的一个位置
return code.charAt(randomIndex);
}
通过genericCheckCode()方法返回随机的字符串位置。
<2>.取出随机生成的验证码
定义一个StringBuffer checkcode,通过循环调用genericCheckCode()方法生成随机字符串位置,使用append()方法追加进checkcode,循环结束后就得到了需要的验证码,再将验证码存入session中
取出随机生成验证码代码如下:
StringBuffer checkcode = new StringBuffer();
//随机生成验证码
for(int i = 0 ; i < 4 ; i++){
checkcode.append(genericCheckCode());
}
String ccstr = checkcode.toString();//得到验证码
request.getSession().setAttribute("checkcode",ccstr);
<3>.画出验证码图片
画出验证码时,首先将验证码画入内存中,然后发送到客户端,画验证码的过程是,首先,使用BufferImage生成44*20的图片缓存区,通过画笔Graphics2D取出画笔对象
,对图片区域填充白色背景,for循环中使用genericNum()方法随机生成随机数,在setColor()方法中对应生成随机颜色,使用substring()方法截取单个字符,g2d.drawString()对这个字符进行绘制。
代码如下:
BufferedImage img = new BufferedImage(44,20, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = (Graphics2D) img.getGraphics();//从图片缓存对象中取出画笔对象(这个对象就是修改缓存区的象素数据的对象)
//填充白色背景
g2d.setColor(new Color(255,255,255));//画笔设置为白色
g2d.fillRect(0,0,44,20);//填充白色背景
//开始画验证码
for(int i = 0 ; i < ccstr.length() ; i++){
g2d.setColor(new Color(genericNum(),genericNum(),genericNum()));//随机生成画笔颜色
String c = ccstr.substring(i,i+1);
g2d.drawString(c,11 * i,16);
}
private int genericNum(){
return new Random().nextInt(200);
<4>.将图片缓存中的图片转换格式
response.setContentType()方法进行发送格式设置,设置发送格式为jpeg图片格式,
JPEGImageEncoder()方法对图片进行压缩
response.setContentType("image/jpeg");
OutputStream output = response.getOutputStream();
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(output);
encoder.encode(img);
3.登录校验
<1>.进行登录校验(数据库连接在重构模块中总结)
进行登录校验前首先应在数据库中添加管理员账号,在登录页面获取表单提交的数据,使用request.getParameter()方法获取表单数据,并从session中取出争取的验证码存入字符串chkcode中,登录校验思路:首先校验验证码是否正确,如果不正确,通过request.getRequestDispatcher().forward(request,response)进行转发,转会登陆页面,并通过setAttribute()方法返回错误信息,如果验证码校验通过,从数据库结果集中取出用户名,密码,首先进行用户名校验,如不通过,则携带错误信息转回登录页面,如果通过,则对密码进行校验,如果密码校验不通过,则携带错误信息转回登录页面,如果通过,创建令牌,转入后台页面。
if(chknumber.equals(chkcode)){
//校验登陆帐号
String sql = "select * from t_user where user = ?" ;
conn = DB.getConnection();
prst = conn.prepareStatement(sql);
prst.setString(1,"admin");
rs = prst.executeQuery();
if(rs.next()){
int id = rs.getInt("uid");
String user1 = rs.getString("user");
String pwd1 = rs.getString("pwd");
if(user1.equals(user) ){
//校验密码
if(pwd1.equals(pwd)){
//创建令牌
User u = new User();
u.setName(user);
u.setLoginTime(new Date());
request.getSession().setAttribute(User.LOGIN_USER,u);
request.getRequestDispatcher("/backend/main.jsp").forward(request,response);
}else{
request.setAttribute("errors","密码名输入错误!");
//转回登陆页面
request.getRequestDispatcher("/backend/login.jsp").forward(request,response);
}
}else{
request.setAttribute("errors","用户名输入错误!");
//转回登陆页面
request.getRequestDispatcher("/backend/login.jsp").forward(request,response);
}
}
}else{
request.setAttribute("errors","验证码输入错误!");
//转回登陆页面
request.getRequestDispatcher("/backend/login.jsp").forward(request,response);
4.问题修正(过滤器)
完成校验后测试无误,但是有逻辑错误,如果用户直接访问后台main.jsp则可以绕过登录页面进入后台进行操作,所以需要定义一个过滤器,将没有持有令牌的用户过滤掉不允许直接访问后台页面。
(过滤器原理)
通过Filter可以使开发人员实现用户访问某个目标资源之前,对访问的请求和相应进行拦截
<1>.令牌设置
定义一个用户类,当访问持有用户类的实例化对象时,就是用户持有令牌,实例化对象应该放在登录校验中密码校验通过的块下。并将对象存入session,以用于验证
代码如下:
public class User { //令牌,需要持有User对象的引用才可以访问后台页面
public static final String LOGIN_USER = "login_user";
private Date loginTime;
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getLoginTime() {
return loginTime;
}
public void setLoginTime(Date loginTime) {
this.loginTime = loginTime;
}
}
<2>.过滤器
定义过滤器CheckLoginFilter,注解为过滤应用范围:/backend/,对req进行类型转换为httpservlet,通过request.getRequestURI()方法获得请求的地址,判断request是否持有令牌,或者与/backend/**.jsp|servlet不匹配的,或者为登录页面,则不进行过滤,否则转到登录页面
@WebFilter(filterName = "CheckLoginFilter",urlPatterns = {"/backend/*"})
public class CheckLoginFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) req;
String requestUri = request.getRequestURI(); //获得访问路径
if(request.getSession().getAttribute(User.LOGIN_USER) != null ||
!requestUri.matches("\\/backend\\/\\w+(\\.jsp|Servlet)") ||
requestUri.equals("/backend/login.jsp")) //判断是否会直接访问后台页面
chain.doFilter(req, resp);
else
request.getRequestDispatcher("/backend/login.jsp").forward(req,resp); //转到登录页面
}
public void init(FilterConfig config) throws ServletException {
}
}