序:

给Shiro加入验证码,有多种方式,当然你也可以通过继承修改FormAuthenticationFilter类,通过Shiro去验证验证码。
具体实现请百度:

应用Shiro到Web Application(验证码实现)

而今天我要说的,既然使用的SpringMVC,为什么不直接在Controller中就处理验证码验证,让事情变的更简单一点呢?


一、新建ValidateCode.java验证码工具类

package org.shiro.demo.util;

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 = ; /**
* 验证码类型为仅字母,即大写、小写字母混合
*/
public static final int TYPE_LETTER_ONLY = ; /**
* 验证码类型为数字、大写字母、小写字母混合
*/
public static final int TYPE_ALL_MIXED = ; /**
* 验证码类型为数字、大写字母混合
*/
public static final int TYPE_NUM_UPPER = ; /**
* 验证码类型为数字、小写字母混合
*/
public static final int TYPE_NUM_LOWER = ; /**
* 验证码类型为仅大写字母
*/
public static final int TYPE_UPPER_ONLY = ; /**
* 验证码类型为仅小写字母
*/
public static final int TYPE_LOWER_ONLY = ; private ValidateCode() { } /**
* 生成验证码字符串
*
* @param type
* 验证码类型,参见本类的静态属性
* @param length
* 验证码长度,大于0的整数
* @param exChars
* 需排除的特殊字符(仅对数字、字母混合型验证码有效,无需排除则为null)
* @return 验证码字符串
*/
public static String generateTextCode(int type, int length, String exChars) { if (length <= )
return ""; StringBuffer code = new StringBuffer();
int i = ;
Random r = new Random(); switch (type) { // 仅数字
case TYPE_NUM_ONLY:
while (i < length) {
int t = r.nextInt();
if (exChars == null || exChars.indexOf(t + "") < ) {// 排除特殊字符
code.append(t);
i++;
}
}
break; // 仅字母(即大写字母、小写字母混合)
case TYPE_LETTER_ONLY:
while (i < length) {
int t = r.nextInt();
if ((t >= || (t >= && t <= )) && (exChars == null || exChars.indexOf((char) t) < )) {
code.append((char) t);
i++;
}
}
break; // 数字、大写字母、小写字母混合
case TYPE_ALL_MIXED:
while (i < length) {
int t = r.nextInt();
if ((t >= || (t >= && t <= ) || (t >= && t <= ))
&& (exChars == null || exChars.indexOf((char) t) < )) {
code.append((char) t);
i++;
}
}
break; // 数字、大写字母混合
case TYPE_NUM_UPPER:
while (i < length) {
int t = r.nextInt();
if ((t >= || (t >= && t <= )) && (exChars == null || exChars.indexOf((char) t) < )) {
code.append((char) t);
i++;
}
}
break; // 数字、小写字母混合
case TYPE_NUM_LOWER:
while (i < length) {
int t = r.nextInt();
if ((t >= || (t >= && t <= )) && (exChars == null || exChars.indexOf((char) t) < )) {
code.append((char) t);
i++;
}
}
break; // 仅大写字母
case TYPE_UPPER_ONLY:
while (i < length) {
int t = r.nextInt();
if ((t >= ) && (exChars == null || exChars.indexOf((char) t) < )) {
code.append((char) t);
i++;
}
}
break; // 仅小写字母
case TYPE_LOWER_ONLY:
while (i < length) {
int t = r.nextInt();
if ((t >= ) && (exChars == null || exChars.indexOf((char) t) < )) {
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(, , width, height); // 画干扰线
Random r = new Random();
if (interLine > ) { int x = , y = , x1 = width, y1 = ;
for (int i = ; 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 = ; 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(), r.nextInt(), r.nextInt());
return c;
} }

二、修改UserController.java的实现

package org.shiro.demo.controller;

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.IOException; import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession; import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.util.WebUtils;
import org.shiro.demo.entity.User;
import org.shiro.demo.util.ValidateCode;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod; @Controller
public class LoginController { @RequestMapping(value = "/login" ,method=RequestMethod.POST,produces={"application/json;charset=UTF-8"})
public String login(User currUser,HttpSession session, HttpServletRequest request){
String code = (String) session.getAttribute("validateCode");
String submitCode = WebUtils.getCleanParam(request, "validateCode");
if (StringUtils.isEmpty(submitCode) || !StringUtils.equals(code,submitCode.toLowerCase())) {
return "redirect:/";
}
Subject user = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(currUser.getAccount(),currUser.getPassword());
token.setRememberMe(true);
try {
user.login(token);
return "/system/main";
}catch (AuthenticationException e) {
token.clear();
return "redirect:/";
}
} /**
* 生成验证码
* @param request
* @param response
* @throws IOException
*/
@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_ONLY, , null);
request.getSession().setAttribute("validateCode", verifyCode);
response.setContentType("image/jpeg");
BufferedImage bim = ValidateCode.generateImageCode(verifyCode, , , , true, Color.WHITE, Color.BLACK, null);
ImageIO.write(bim, "JPEG", response.getOutputStream());
}
}

三、修改login.jsp

<%@ page language="java" pageEncoding="utf-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path;
%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>shirodemo login page</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<script type="text/javascript" src='<c:url value="/resources/js/jquery-1.6.3.min.js"/>'></script>
<script type="text/javascript">
<!--
function reloadValidateCode(){
$("#validateCodeImg").attr("src","<%=basePath%>/validateCode?data=" + new Date() + Math.floor(Math.random()*));
}
//-->
</script>
</head> <body>
<form action="<%=basePath%>/login" method="post">
<ul>
<li>姓 名:<input type="text" name="account" /> </li>
<li>密 码:<input type="text" name="password" /> </li>
<li>验证码:<input type="text" name="validateCode" />&nbsp;&nbsp;<img id="validateCodeImg" src="<%=basePath%>/validateCode" />&nbsp;&nbsp;<a href="#" onclick="javascript:reloadValidateCode();">看不清?</a></li>
<li><input type="submit" value="确认" /> </li>
</ul>
</form>
</body>
</html>

至此,就给你的登陆页面加上验证码了。访问你的login.jsp试试?

转自:http://www.cnblogs.com/xql4j/archive/2013/03/30/2990998.html

SpringMVC+Apache Shiro+JPA(hibernate)案例教学(三)给Shiro登录验证加上验证码的更多相关文章

  1. Apache shiro集群实现 (三)shiro身份认证(Shiro Authentication)

    Apache shiro集群实现 (一) shiro入门介绍 Apache shiro集群实现 (二) shiro 的INI配置 Apache shiro集群实现 (三)shiro身份认证(Shiro ...

  2. Apache Shiro:【2】与SpringBoot集成完成登录验证

    Apache Shiro:[2]与SpringBoot集成完成登录验证 官方Shiro文档:http://shiro.apache.org/documentation.html Shiro自定义Rea ...

  3. SpringMVC+Apache Shiro+JPA(hibernate)

    http://my.oschina.net/moziqi/blog/305412 http://my.oschina.net/miger/blog/283526 spring4.1.0+spring ...

  4. maven springmvc spring data jpa hibernate sqlserver demo

    搭建费了半天费,各种报错,缺少各种jar包,不兼容等,给那些没弄过的一个参考. 点击我下载

  5. Shiro 安全框架详解一(概念+登录案例实现)

    shiro 安全框架详细教程 总结内容 一.RBAC 的概念 二.两种常用的权限管理框架 1. Apache Shiro 2. Spring Security 3. Shiro 和 Spring Se ...

  6. Apache shiro集群实现 (四)shiro授权(Authentication)--访问控制

    Apache shiro集群实现 (一) shiro入门介绍 Apache shiro集群实现 (二) shiro 的INI配置 Apache shiro集群实现 (三)shiro身份认证(Shiro ...

  7. Apache shiro集群实现 (二) shiro 的INI配置

    Apache shiro集群实现 (一) shiro入门介绍 Apache shiro集群实现 (二) shiro 的INI配置 Apache shiro集群实现 (三)shiro身份认证(Shiro ...

  8. Apache shiro集群实现 (一) shiro入门介绍

    近期在ITOO项目中研究使用Apache shiro集群中要解决的两个问题,一个是Session的共享问题,一个是授权信息的cache共享问题,官网上给的例子是Ehcache的实现,在配置说明上不算很 ...

  9. SpringMVC+Apache Shiro+JPA(hibernate)案例教学(二)基于SpringMVC+Shiro的用户登录权限验证

    序: 在上一篇中,咱们已经对于项目已经做了基本的配置,这一篇文章开始学习Shiro如何对登录进行验证. 教学: 一.Shiro配置的简要说明. 有心人可能注意到了,在上一章的applicationCo ...

随机推荐

  1. servlet中 java.lang.ClassNotFoundException: com.mysql.jdbc.Driver异常

    解决方法:将mysql-connector-java-xxx-bin.jar包,复制到项目下WebContent/WEB-INF/lib目录下,刷新重启tomcat运行即可.

  2. 隐写术之steghide的使用

    steghide不是一个软件,所以下载之后解压缩就可以在命令行中使用. win+R,cmd,回车->进入到steghide.exe所在的文件夹,使用隐藏或者解锁的相应命令,即可隐藏或者解锁. 这 ...

  3. nginx 常见正则匹配符号表示

    1.^: 匹配字符串的开始位置: 2. $:匹配字符串的结束位置: 3..*: .匹配任意字符,*匹配数量0到正无穷: 4.\. 斜杠用来转义,\.匹配 . 特殊使用方法,记住记性了: 5.(值1|值 ...

  4. 如何注册一个google账号

    注册过google账号的人都知道,在注册的过程中会需要短信验证. 可我大天朝偏偏连这个都锁了,导致根本验证不了. 所以,经过网上方法的不断尝试,排除了很多的方法:例如使用qq邮箱注册等,现在已经不能用 ...

  5. 揽货最短路径解决方案算法 - V2(增加了时间维度-客户允许的服务时间段,C#/JAVA同步实现,带python作图)

    继上篇,这里改进增加了客户允许服务的时间范围这个维度,并且把C#版本翻译成java,加强了更加形象的图表展示路径(继续是用python的matplotlib作图). 这里的时间范围维度是指:每个客户都 ...

  6. 按PEP8风格自动排版Python代码

    Autopep8是一个将Python代码自动排版为PEP8风格的小工具.它使用pep8工具来决定代码中的哪部分需要被排版.Autopep8可以修复大部分pep8工具中报告的排版问题. 安装步骤如下: ...

  7. springboot启动关闭脚本

    springboot项目jar包启动,application.properties.jar包.shell脚本.static目录(静态页面和jar包分离)在同一目录下 [start.sh] #!/bin ...

  8. 在vue 里使用腾讯ditu

    https://www.cnblogs.com/mrer/p/7144705.html

  9. C语言博客作业02--循环结构

    1.本章学习总结 1.1 思维导图 1.2 本章学习体会及代码量学习体会 1.2.1 学习体会 经过本周学习,对c循环结构有了深入,无论是单层循环结构还是嵌套循环结构的问题,我都学会有一定的解决能力, ...

  10. -bash: fork: Cannot allocate memory 问题的处理

    今天生产机器突然无法登录了,正好有一个用top挂着,但是退出top,执行任何命令都报-bash: fork: Cannot allocate memory,但是查看内存还是有很多空闲,然后在百度上查了 ...