序:

给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. Python 爬虫基础Selenium

    https://blog.csdn.net/weixin_36279318/article/details/79475388

  2. jeecg入门操作—菜单管理

    一.菜单配置入口 登录jeecg平台,点击系统管理->菜单管理,弹出菜单管理界面 二.配置一级菜单 点击菜单录入 三.配置二级菜单 选中生成的一级菜单,点击菜单录入  四.菜单授权  五.注销系 ...

  3. 03-MySQL表操作

    MySQL表操作 1.介绍 表就相当于文件,表中的一条记录就相当与文件的一行内容,不同的是,表中的一条记录有对应的标题,成为表的字段. 2.创建表 2.1语法 create table 表名( 字段名 ...

  4. scala的多种集合的使用(4)之列表List(ListBuffer)的操作

    1.List列表的创建和添加元素 1)最常见的创建list的方式之一. scala> val list = 1 :: 2 :: 3 :: Nil list: List[Int] = List(1 ...

  5. c++ 套路多

    1. 浅拷贝带来的多次析构问题 参见:https://www.cnblogs.com/33debug/p/6657730.html 解决方案,深拷贝.强烈建议自定义拷贝构造函数为深拷贝,否则可能会给自 ...

  6. MySQL数据库8.0.15 安装教程

    第一步:安装MySQL服务 这里下载完成的是一个压缩文件,直接将里面的‘mysql-8.0.15-winx64'文件夹解压到你想要安装的路径即可,我是直接安装在C盘的. 解压完后的文件路径如下图: 在 ...

  7. MySQL 的数据目录

    MySQL里面有4个数据库是属于MySQL自带的系统数据库: mysql 这个数据库贼核心,它存储了MySQL的用户账户和权限信息,一些存储过程.事件的定义信息,一些运行过程中产生的日志信息,一些帮助 ...

  8. icpc 南昌邀请赛网络赛 Max answer

    就是求区间和与区间最小值的积的最大值 但是a[i]可能是负的 这就很坑 赛后看了好多dalao的博客 终于a了 这个问题我感觉可以分为两个步骤 第一步是对于每个元素 以它为最小值的最大区间是什么 第二 ...

  9. jQuery 源码学习 - 01 - 简洁的 $('...')

    首先贴上学习参考资料:[深入浅出jQuery]源码浅析--整体架构,备用地址:chokcoco/jQuery-. jQuery 库,js 开发的一个里程碑,它的出现,让网页开发者们告别荒蛮的上古时代, ...

  10. hdu-4612(无向图缩点+树的直径)

    题意:给你n个点和m条边的无向图,问你如果多加一条边的话,那么这个图最少的桥是什么 解题思路:无向图缩点和树的直径,用并查集缩点: #include<iostream> #include& ...