序:

给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. 弱网测试-Network Emulator 网络模拟工具使用

    参考链接 https://www.jianshu.com/p/6a3d38aafac1

  2. ztree 获取子节点所有父节点的name的拼接

    ztree 获取子节点所有父节点的name的拼接 //获取子节点,所有父节点的name的拼接字符串function getFilePath(treeObj){if(treeObj==null)retu ...

  3. 菜鸟学IT-分布式版本控制系统Git的安装与使用

    分布式版本控制系统Git的安装与使用 本次作业要求来于:https://edu.cnblogs.com/campus/gzcc/GZCC-16SE1/homework/2103 一.首先在window ...

  4. Docker部署脚本

    实现 1.检查内核版本 2.检查docker是否已安装 3.安装docker,如因网络等原因失败循环安装至安装完成 #!/bin/bash #file:docker_install.sh #From: ...

  5. SpringCloud---网关概念、Zuul项目搭建(六)

    SpringCloud---网关概念.Zuul项目搭建(六) 一.网关概念 1.什么是路由网关 网关是系统的唯一对外的入口,介于客户端和服务器端之间的中间层,处理非业务功能 提供路由请求.鉴权.监控. ...

  6. Python——pyqt5——各框架编程

    一.日期时间(dateTimeEdit/dateEdit) setDateTime:设置日期(含时间) QDateTime.currentDateTime():当前日期(含时间) setDate:设置 ...

  7. 最长公共子序列(POJ1458)

    给出两个字符串,求出这样的一个最长的公共子序列的长度:子序列中的每个字符都能在两个原串中找到,而且每个字符的先后顺序和原串中的先后顺序一致. Sample Input: abcfbc abfcabpr ...

  8. jmap -histo pid 输出的[C [B [I [S methodKlass constantPoolKlass含义

    jmap -histo pid 输出的[C [B [I [S methodKlass constantPoolKlass含义 2014年01月16日 11:00:12 lxb_champagne 阅读 ...

  9. Python实现FTP文件的上传和下载

    # coding: utf-8 import os from ftplib import FTP def ftp_connect(host, username, password): ftp = FT ...

  10. mybatis-generator自动生成代码插件

    mybatis自动生成代码(实体类.Dao接口等)是很成熟的了,就是使用mybatis-generator插件. 它是一个开源的插件,使用maven构建最好,可以很方便的执行 插件官方简介: http ...