1.js的编写
//更换图片
function changeImg(){
var imgSrc = $("#imgObj");
var src = imgSrc.attr("src");
imgSrc.attr("src",chgUrl(src));
}
//时间戳
//为了使每次生成图片不一致,即不让浏览器读缓存,所以需要加上时间戳
function chgUrl(url){
var timestamp = (new Date()).valueOf();
if((url.indexOf("&")>=0)){
url = url + "×tamp=" + timestamp;
}else{
url = url + "?timestamp=" + timestamp;
}
return url;
}
2.生成验证码图片的代码
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
/**
* Created by funian on 2018/7/12.
*/
@WebServlet(urlPatterns="/verifyCodeServlet", description="生成验证码")
public class VerifyCodeServlet extends HttpServlet {
private Logger LOGGER = LoggerFactory.getLogger(VerifyCodeServlet.class);
private static final int WIDTH = 70;// 验证码图片的宽度。
private static final int HEIGHT = 34;// 验证码图片的高度。
private static final int CODE_COUNT = 4;// 验证码字符个数
private Random r = new Random();
// 定义有那些字体 { "宋体", "华文楷体", "黑体", "微软雅黑", "楷体_GB2312" };
private String[] fontNames = { "华文楷体"};
// 定义有那些验证码的随机字符
private String codes = "123456789abcdefghjkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ";
// 用于gettext 方法 获得生成的验证码文本
private String text = "";
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp){
//生成图片
BufferedImage buffImg = createImage();
// 将四位的验证码保存到Session中
String validateCode = getText();
HttpSession session = req.getSession();
session.setAttribute("validateCode", validateCode);
// 禁止图像缓存。
resp.setHeader("Pragma", "no-cache");
resp.setHeader("Cache-Control", "no-cache");
resp.setDateHeader("Expires", 0);
resp.setContentType("image/jpeg");
// 将图像输出到Servlet输出流中。
try (ServletOutputStream sos = resp.getOutputStream()){
ImageIO.write(buffImg, "jpeg", sos);
} catch (IOException e) {
LOGGER.error("生成验证码异常", e);
}
}
// 得到验证码的文本 后面是用来和用户输入的验证码 检测用
public String getText() {
return text;
}
// 生成随机颜色
private Color randomColor() {
// int red = r.nextInt(150);
// int green = r.nextInt(150);
// int blue = r.nextInt(150);
return new Color(44, 47, 250);
}
// 生成随机字体
private Font randomFont() {
int index = r.nextInt(fontNames.length);
String fontName = fontNames[index];//生成随机的字体名称
int style = r.nextInt(3);//生成随机的样式, 0(无样式), 1(粗体), 2(斜体), 3(粗体+斜体)
int size = r.nextInt(5) + 24;//生成随机字号, 24 ~ 28
return new Font(fontName, style, size);
}
// 画干扰线
private void drawLine(BufferedImage image) {
int num = 3;//一共画3条
Graphics2D g2 = (Graphics2D) image.getGraphics();
for (int i = 0; i < num; i++) {
int x1 = r.nextInt(WIDTH);
int y1 = r.nextInt(HEIGHT);
int x2 = r.nextInt(WIDTH);
int y2 = r.nextInt(HEIGHT);
g2.setStroke(new BasicStroke(1.5F));
g2.setColor(Color.blue);//干扰线是蓝色
g2.drawLine(x1, y1, x2, y2);
}
}
// 得到codes的长度内的随机数 并使用charAt 取得随机数位置上的codes中的字符
private char randomChar() {
int index = r.nextInt(codes.length());
return codes.charAt(index);
}
// 创建BufferedImage
private BufferedImage getImage () {
BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = (Graphics2D)image.getGraphics();
g2.setColor(Color.WHITE);
g2.fillRect(0, 0, WIDTH, HEIGHT);
return image;
}
// 创建一张验证码的图片
public BufferedImage createImage() {
BufferedImage image = getImage ();
Graphics2D g2 = (Graphics2D)image.getGraphics();
StringBuilder sb = new StringBuilder();
// 向图中画字符
for (int i = 0; i < CODE_COUNT; i++) {
String s = randomChar() + "";
sb.append(s);
float x = i * 1.0F * WIDTH / 4;//设置当前字符的x轴坐标
g2.setFont(randomFont());//设置随机字体
g2.setColor(randomColor());//设置随机颜色
g2.drawString(s, x, HEIGHT - 5);//画图
}
this.text = sb.toString();
//添加干扰线
drawLine(image);
// 返回图片
return image;
}
}
3.拦截器的验证码代码
import im.lsn.framework.jpa.JpaRepositoryImpl;
import im.lsn.framework.shrio.CustomSecurityException;
import im.lsn.oss.exhibition.entity.QTbUser;
import im.lsn.oss.exhibition.entity.TbUser;
import im.lsn.oss.exhibition.entity.enumerate.LoginType;
import im.lsn.oss.exhibition.service.ClickedCountService;
import im.lsn.oss.exhibition.service.CustomizedToken;
import im.lsn.oss.exhibition.service.SecurityService;
import im.lsn.oss.exhibition.service.UserLoginToken;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.beans.factory.annotation.Autowired;
import javax.annotation.PostConstruct;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
public class AdminFilter extends FormAuthenticationFilter {
protected String getCaptcha(ServletRequest request) {
return WebUtils.getCleanParam(request, "captcha");
}
public AdminFilter() {
}
@Autowired
private SecurityService securityService;
@Autowired
private ClickedCountService clickedCountService;
@PersistenceContext
protected EntityManager entityManager;
private JpaRepositoryImpl<TbUser, Long> userRepository;
@PostConstruct
public void initSecurityService() {
this.userRepository = new JpaRepositoryImpl<TbUser, Long>(TbUser.class, entityManager);
}
@Override
protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
Subject subject = SecurityUtils.getSubject();
if (subject != null) {
UserLoginToken loginToken = (UserLoginToken) subject.getPrincipal();
if (loginToken != null && loginToken.getType().equalsIgnoreCase(LoginType.FRONT.toString())) {
securityService.logout();
}
}
return super.preHandle(request, response);
}
protected CustomizedToken createToken(ServletRequest request, ServletResponse response) {
String username = this.getUsername(request);
String password = this.getPassword(request);
String captcha = this.getCaptcha(request);
boolean rememberMe = this.isRememberMe(request);
String host = this.getHost(request);
String type = LoginType.ADMIN.toString();
return new CustomizedToken(username, password.toCharArray(), rememberMe, host, captcha, type);
}
protected void setFailureAttribute(ServletRequest request, AuthenticationException ae) {
String failureMessage = this.getFailureKeyAttribute() + ".message";
if (ae instanceof CustomSecurityException) {
if(StringUtils.equals("用户名或密码错误",ae.getMessage())){
QTbUser qUser = QTbUser.tbUser;
TbUser user = userRepository.findOne(qUser.username.eq(((ShiroHttpServletRequest) request).getCookies()[1].getValue()));
Integer count = user.getClickedCount();
count++;
clickedCountService.updateClickedCount(user.getId(),count);
}
request.setAttribute(failureMessage, ae.getMessage());
}
if (ae instanceof UnknownAccountException) {
request.setAttribute(failureMessage, "用户不存在 ");
}
if (ae instanceof IncorrectCredentialsException) {
request.setAttribute(failureMessage, "密码错误");
}
super.setFailureAttribute(request, ae);
}
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
String failureMessage = this.getFailureKeyAttribute() + ".message";
// 在这里进行验证码的校验
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpSession session = httpServletRequest.getSession();
// 取出验证码
String validateCode = (String) session.getAttribute("validateCode");
// 取出页面的验证码
// 输入的验证和session中的验证进行对比
String randomcode = httpServletRequest.getParameter("veryCode");
if (StringUtils.isNotBlank(randomcode)&& StringUtils.isNotBlank(validateCode)&&!randomcode.equalsIgnoreCase(validateCode)){
request.setAttribute(failureMessage,"验证码错误");
QTbUser qUser = QTbUser.tbUser;
TbUser user = userRepository.findOne(qUser.username.eq(((ShiroHttpServletRequest) request).getCookies()[1].getValue()));
if(null!=user){
Integer count = user.getClickedCount();
count++;
clickedCountService.updateClickedCount(user.getId(),count);
}
return true;
}
return super.onAccessDenied(request, response);
}
@Override
protected void issueSuccessRedirect(ServletRequest request, ServletResponse response) throws Exception {
QTbUser qUser = QTbUser.tbUser;
TbUser user = userRepository.findOne(qUser.username.eq(((ShiroHttpServletRequest) request).getCookies()[1].getValue()));
clickedCountService.updateClickedCount(user.getId(),0);
WebUtils.issueRedirect(request, response, this.getSuccessUrl(), null, true);
}
}
4.前端的验证码
<div class="row">
<div class="col-xs-9">
<div class="form-group has-feedback">
<input id="veryCode" name="veryCode" maxlength="4" class="form-control codeVal" type="text" placeholder="验证码" required />
<span class="glyphicon glyphicon-option-horizontal form-control-feedback"></span>
</div>
</div>
<div class="col-xs-3">
<img id="imgObj" align="right" alt="" onclick="changeImg()" src="${ctxRoot}/verifyCodeServlet"/>
</div>
</div>
5.前端的验证码的js格式验证
// 验证码校验
jQuery.validator.addMethod("codeVal", function(value, element) {
var reg = /^[a-zA-Z0-9]{4}$/;
return this.optional(element) || (reg.test(value));
}, "请输入正确的验证码!");
来源:https://www.cnblogs.com/ly-lyq/p/9965061.html