序:

给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. windows本地远程虚拟机docker中的数据的问题

    关闭各种防火墙 打开宿主机(windows)的cmd,在其中添加通往192.168.1.0/24网络的路由. 通往192.168.1.0/24网络的数据包由172.20.1.12来转发 route a ...

  2. scala的多种集合的使用(5)之数组Array(ArrayBuffer)的操作

    1.创建和更新数组的不同方式 1)定义一个数组的初始大小和类型,随后填充值. scala> val array = new Array[String](3) array: Array[Strin ...

  3. Fedora中安装VMtools步骤

    第一次玩Fedora的系统,通过VMware工具安装的一个虚拟机,由于公司要求尽可能的留有足够空间,所以安装的时候就没选开发环境选项.安装成功后,又要准备安装VMware--tools工具,在此记录安 ...

  4. 微信小程序域名

    微信小程序与第三方服务器通讯的域名必要条件1.一个已备案的域名,不是localhost.也不是127.0.0.1,域名不能加端口2.加ssl证书,也就是https://~~~3.HTTPS 服务器的 ...

  5. WebApi(五)-Swagger接口文档①简单集成

    1,通过NuGet引用Swashbuckle 2,打开项目属性-->生成,勾选XML文档文件,保存 3,找到项目App_Start文件夹下WebApiConfig查找GetXmlComments ...

  6. jexus独立版设置支持https

    先用命令找到libssl.so find / -name libssl.so.* 执行完命令之后找到libssl.so.x.x.x如(libssl.so.1.0.0) 再到jexus/runtime/ ...

  7. AtCoder ABC 042D いろはちゃんとマス目 / Iroha and a Grid

    题目链接:https://abc042.contest.atcoder.jp/tasks/arc058_b 题目大意: 给定一个 H * W 的矩阵,其中左下角 A * B 区域是禁区,要求在不踏入禁 ...

  8. centos7之zabbix监控mysql(mariadb)数据库

    一.Zabbix3.2.6使用自带模板监控MySQL 添加zabbix_agent客户端方法:http://www.cnblogs.com/lei0213/p/8858269.html mysql服务 ...

  9. 洛谷 P2325 [SCOI2005]王室联邦

    简化版题意: 一个国家由\(n\)个城市组成一颗树,要将其划分为\(n\)个省 每个城市大小为\([B,3B]\),每个省有一个省会(不一定要在省内),使得每个省的所有城市到省会的路径上不能经过其他省 ...

  10. 【集训队互测2015】Robot

    题目描述 http://uoj.ac/problem/88 题解 维护两颗线段树,维护最大值和最小值,因为每次只有单点查询,所以可以直接在区间插入线段就可以了. 注意卡常,不要写STL,用链表把同类修 ...