当前位置: 移动技术网 > IT编程>开发语言>Java > Java中SSM+Shiro系统登录验证码的实现方法

Java中SSM+Shiro系统登录验证码的实现方法

2019年07月22日  | 移动技术网IT编程  | 我要评论

 先给大家展示下效果图:

1、验证码生成类:

import java.util.random;
import java.awt.image.bufferedimage;
import java.awt.graphics;
import java.awt.font;
import java.awt.color;
/**
 * 验证码生成器类,可生成数字、大写、小写字母及三者混合类型的验证码。 支持自定义验证码字符数量; 支持自定义验证码图片的大小; 支持自定义需排除的特殊字符;
 * 支持自定义干扰线的数量; 支持自定义验证码图文颜色
 */
public class validatecode {
 /**
  * 验证码类型为仅数字 0~9
  */
 public static final int type_num_only = 0;
 /**
  * 验证码类型为仅字母,即大写、小写字母混合
  */
 public static final int type_letter_only = 1;
 /**
  * 验证码类型为数字、大写字母、小写字母混合
  */
 public static final int type_all_mixed = 2;
 /**
  * 验证码类型为数字、大写字母混合
  */
 public static final int type_num_upper = 3;
 /**
  * 验证码类型为数字、小写字母混合
  */
 public static final int type_num_lower = 4;
 /**
  * 验证码类型为仅大写字母
  */
 public static final int type_upper_only = 5;
 /**
  * 验证码类型为仅小写字母
  */
 public static final int type_lower_only = 6;
 private validatecode() {
 }
 /**
  * 生成验证码字符串
  * 
  * @param type
  *   验证码类型,参见本类的静态属性
  * @param length
  *   验证码长度,大于0的整数
  * @param exchars
  *   需排除的特殊字符(仅对数字、字母混合型验证码有效,无需排除则为null)
  * @return 验证码字符串
  */
 public static string generatetextcode(int type, int length, string exchars) {
  if (length <= 0)
   return "";
  stringbuffer code = new stringbuffer();
  int i = 0;
  random r = new random();
  switch (type) {
  // 仅数字
  case type_num_only:
   while (i < length) {
    int t = r.nextint(10);
    if (exchars == null || exchars.indexof(t + "") < 0) {// 排除特殊字符
     code.append(t);
     i++;
    }
   }
   break;
  // 仅字母(即大写字母、小写字母混合)
  case type_letter_only:
   while (i < length) {
    int t = r.nextint(123);
    if ((t >= 97 || (t >= 65 && t <= 90)) && (exchars == null || exchars.indexof((char) t) < 0)) {
     code.append((char) t);
     i++;
    }
   }
   break;
  // 数字、大写字母、小写字母混合
  case type_all_mixed:
   while (i < length) {
    int t = r.nextint(123);
    if ((t >= 97 || (t >= 65 && t <= 90) || (t >= 48 && t <= 57))
      && (exchars == null || exchars.indexof((char) t) < 0)) {
     code.append((char) t);
     i++;
    }
   }
   break;
  // 数字、大写字母混合
  case type_num_upper:
   while (i < length) {
    int t = r.nextint(91);
    if ((t >= 65 || (t >= 48 && t <= 57)) && (exchars == null || exchars.indexof((char) t) < 0)) {
     code.append((char) t);
     i++;
    }
   }
   break;
  // 数字、小写字母混合
  case type_num_lower:
   while (i < length) {
    int t = r.nextint(123);
    if ((t >= 97 || (t >= 48 && t <= 57)) && (exchars == null || exchars.indexof((char) t) < 0)) {
     code.append((char) t);
     i++;
    }
   }
   break;
  // 仅大写字母
  case type_upper_only:
   while (i < length) {
    int t = r.nextint(91);
    if ((t >= 65) && (exchars == null || exchars.indexof((char) t) < 0)) {
     code.append((char) t);
     i++;
    }
   }
   break;
  // 仅小写字母
  case type_lower_only:
   while (i < length) {
    int t = r.nextint(123);
    if ((t >= 97) && (exchars == null || exchars.indexof((char) t) < 0)) {
     code.append((char) t);
     i++;
    }
   }
   break;
  }
  return code.tostring();
 }
 /**
  * 已有验证码,生成验证码图片
  * 
  * @param textcode
  *   文本验证码
  * @param width
  *   图片宽度
  * @param height
  *   图片高度
  * @param interline
  *   图片中干扰线的条数
  * @param randomlocation
  *   每个字符的高低位置是否随机
  * @param backcolor
  *   图片颜色,若为null,则采用随机颜色
  * @param forecolor
  *   字体颜色,若为null,则采用随机颜色
  * @param linecolor
  *   干扰线颜色,若为null,则采用随机颜色
  * @return 图片缓存对象
  */
 public static bufferedimage generateimagecode(string textcode, int width, int height, int interline,
   boolean randomlocation, color backcolor, color forecolor, color linecolor) {
  bufferedimage bim = new bufferedimage(width, height, bufferedimage.type_int_rgb);
  graphics g = bim.getgraphics();
  // 画背景图
  g.setcolor(backcolor == null ? getrandomcolor() : backcolor);
  g.fillrect(0, 0, width, height);
  // 画干扰线
  random r = new random();
  if (interline > 0) {
   int x = 0, y = 0, x1 = width, y1 = 0;
   for (int i = 0; i < interline; i++) {
    g.setcolor(linecolor == null ? getrandomcolor() : linecolor);
    y = r.nextint(height);
    y1 = r.nextint(height);
    g.drawline(x, y, x1, y1);
   }
  }
  // 写验证码
  // g.setcolor(getrandomcolor());
  // g.setcolor(issimplecolor?color.black:color.white);
  // 字体大小为图片高度的80%
  int fsize = (int) (height * 0.8);
  int fx = height - fsize;
  int fy = fsize;
  g.setfont(new font("default", font.plain, fsize));
  // 写验证码字符
  for (int i = 0; i < textcode.length(); i++) {
   fy = randomlocation ? (int) ((math.random() * 0.3 + 0.6) * height) : fy;// 每个字符高低是否随机
   g.setcolor(forecolor == null ? getrandomcolor() : forecolor);
   g.drawstring(textcode.charat(i) + "", fx, fy);
   fx += fsize * 0.9;
  }
  g.dispose();
  return bim;
 }
 /**
  * 生成图片验证码
  * 
  * @param type
  *   验证码类型,参见本类的静态属性
  * @param length
  *   验证码字符长度,大于0的整数
  * @param exchars
  *   需排除的特殊字符
  * @param width
  *   图片宽度
  * @param height
  *   图片高度
  * @param interline
  *   图片中干扰线的条数
  * @param randomlocation
  *   每个字符的高低位置是否随机
  * @param backcolor
  *   图片颜色,若为null,则采用随机颜色
  * @param forecolor
  *   字体颜色,若为null,则采用随机颜色
  * @param linecolor
  *   干扰线颜色,若为null,则采用随机颜色
  * @return 图片缓存对象
  */
 public static bufferedimage generateimagecode(int type, int length, string exchars, int width, int height,
   int interline, boolean randomlocation, color backcolor, color forecolor, color linecolor) {
  string textcode = generatetextcode(type, length, exchars);
  bufferedimage bim = generateimagecode(textcode, width, height, interline, randomlocation, backcolor, forecolor,
    linecolor);
  return bim;
 }
 /**
  * 产生随机颜色
  * 
  * @return
  */
 private static color getrandomcolor() {
  random r = new random();
  color c = new color(r.nextint(255), r.nextint(255), r.nextint(255));
  return c;
 }
}

2、controller

 /**
  * 生成验证码
  * @param request
  * @param response
  * @throws ioexception
  * @validatecode.generatetextcode(验证码字符类型,验证码长度,需排除的特殊字符)
  * @validatecode.generateimagecode(文本验证码,图片宽度,图片高度,干扰线的条数,字符的高低位置是否随机,图片颜色,字体颜色,干扰线颜色)
  */
 @requestmapping(value = "validatecode")
 public void validatecode(httpservletrequest request, httpservletresponse response) throws ioexception {
  response.setheader("cache-control", "no-cache");
  string verifycode = validatecode.generatetextcode(validatecode.type_num_lower, 4, null);
  request.getsession().setattribute("validatecode", verifycode);
  response.setcontenttype("image/jpeg");
  bufferedimage bim = validatecode.generateimagecode(verifycode, 90, 30, 5, true, color.white, color.blue, null);
  imageio.write(bim, "jpeg", response.getoutputstream());
 }
 /**
  * 登录请求
  * @param 
  */
 @requestmapping(value = "login", method = requestmethod.post, produces = "text/html; charset=utf-8")
 public string login(httpservletrequest request, httpservletresponse response, userentity user) {
  //首先进行验证码验证
  session session = securityutils.getsubject().getsession();
  string code = (string) session.getattribute("validatecode");
  string submitcode = webutils.getcleanparam(request, "validatecode");
  if (stringutils.isempty(submitcode) || !stringutils.equals(code,submitcode.tolowercase())) {
   request.setattribute("login_error_code", loginconstant.login_error_code_100000);
   request.setattribute("login_error_message", loginconstant.login_error_message_validatecode);
   return "login";
  }
  // 想要得到 securityutils.getsubject() 的对象..访问地址必须跟shiro的拦截地址内.不然后会报空指针
  subject sub = securityutils.getsubject();
  // 用户输入的账号和密码,,存到usernamepasswordtoken对象中..然后由shiro内部认证对比,
  // 认证执行者交由shirodbrealm中dogetauthenticationinfo处理
  // 当以上认证成功后会向下执行,认证失败会抛出异常
  usernamepasswordtoken token = new usernamepasswordtoken(user.getaccountname(), user.getpassword());
  try {
   sub.login(token);
  } catch (lockedaccountexception lae) {
   token.clear();
   request.setattribute("login_error_code", loginconstant.login_error_code_100002);
   request.setattribute("login_error_message", loginconstant.login_error_message_systemerror);
   return "login";
  } catch (excessiveattemptsexception e) {
   token.clear();
   request.setattribute("login_error_code", loginconstant.login_error_code_100003);
   request.setattribute("login_error_message","账号:" + user.getusername() + loginconstant.login_error_message_maxerror);
   return "login";
  } catch (authenticationexception e) {
   token.clear();
   request.setattribute("login_error_code", loginconstant.login_error_code_100001);
   request.setattribute("login_error_message", loginconstant.login_error_message_usererror);
   return "login";
  }
  return "redirect:/index.shtml";
 }

注意:

登录方法里面一些参数的定义:

public interface loginconstant
{
 string login_error_code_100000 = "100000";
 string login_error_message_validatecode = "验证码输入错误,请重新输入!";
 string login_error_code_100001 = "100001";
 string login_error_message_usererror = "账号或密码错误,请重新输入!";
 string login_error_code_100002 = "100002";
 string login_error_message_systemerror = "用户已经被锁定不能登录,请与管理员联系!";
 string login_error_code_100003 = "100003";
 string login_error_message_maxerror = "登录失败次数过多,锁定10分钟!";
 string login_error_code_100004 = "100004";
 string login_error_message_forcelogout = "您已经被管理员强制退出,请重新登录";
}

3、登录jsp(重要代码)

路径信息:

<%
string path = request.getcontextpath();
string basepath = request.getscheme()+"://"+request.getservername()+":"+request.getserverport()+path;
%>

js:用于更换验证码图片

 <script>
  function reloadvalidatecode(){
   $("#validatecodeimg").attr("src","<%=basepath%>/validatecode.shtml?data=" + new date() + math.floor(math.random()*24));
  }
 </script>

登录表单里面的标签:

<img id="validatecodeimg" src="<%=basepath%>/validatecode.shtml" />  <a href="#" rel="external nofollow" onclick="javascript:reloadvalidatecode();">看不清?</a>

4、shiro匿名访问配置(不配置无法生成验证码图片)

<!--自定义filterchaindefinitionmap -->
 <bean id="chaindefinitionsectionmetasource" class="com.collection.shiro.chaindefinitionsectionmetasource">
  <property name="filterchaindefinitions">
   <value>
    /validatecode.shtml = anon//添加这行
   </value>
  </property>
 </bean>

以上所述是小编给大家介绍的java中ssm+shiro系统登录验证码的实现方法,希望对大家有所帮助

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网