首页 > 编程 > Java > 正文

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

2019-11-26 13:04:45
字体:
来源:转载
供稿:网友

 先给大家展示下效果图:

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系统登录验证码的实现方法,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对武林网网站的支持!

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表