SpringBoot整合Spring Security,使用Session方式的验证码(六)
一、导入验证码库的依赖
<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
<version>2.3.2</version>
<exclusions>
<exclusion>
<artifactId>javax.servlet-api</artifactId>
<groupId>javax.servlet</groupId>
</exclusion>
</exclusions>
</dependency>
二、然后写一个kaptcha.properties配置文件:
kaptcha.border=no
kaptcha.border.color=105,179,90
kaptcha.image.width=100
kaptcha.image.height=45
kaptcha.session.key=code
kaptcha.textproducer.font.color=blue
kaptcha.textproducer.font.size=35
kaptcha.textproducer.char.length=4
kaptcha.textproducer.font.names=宋体,楷体,微软雅黑
需要注意的是这里的中文可能是乱码,改下文件格式即可:
三、配置验证码生成类
package com.example.securityzimug.config.auth.imagecode;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import java.util.Properties;
/**
* @author baikunlong
* @date 2020/9/23 15:34
*/
@Configuration
@PropertySource(value = {"classpath:kaptcha.properties"})
public class CaptchaConfig {
@Value("${kaptcha.border}")
private String border;
@Value("${kaptcha.border.color}")
private String borderColor;
@Value("${kaptcha.textproducer.font.color}")
private String fontColor;
@Value("${kaptcha.image.width}")
private String imageWidth;
@Value("${kaptcha.image.height}")
private String imageHeight;
@Value("${kaptcha.session.key}")
private String sessionKey;
@Value("${kaptcha.textproducer.char.length}")
private String charLength;
@Value("${kaptcha.textproducer.font.names}")
private String fontNames;
@Value("${kaptcha.textproducer.font.size}")
private String fontSize;
@Bean
public DefaultKaptcha getKaptchaBean(){
DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
Properties properties = new Properties();
properties.setProperty("kaptcha.border", border);
properties.setProperty("kaptcha.border.color", borderColor);
properties.setProperty("kaptcha.textproducer.font.color", fontColor);
properties.setProperty("kaptcha.image.width", imageWidth);
properties.setProperty("kaptcha.image.height", imageHeight);
properties.setProperty("kaptcha.session.key", sessionKey);
properties.setProperty("kaptcha.textproducer.char.length", charLength);
properties.setProperty("kaptcha.textproducer.font.names", fontNames);
properties.setProperty("kaptcha.textproducer.font.size",fontSize);
defaultKaptcha.setConfig(new Config(properties));
return defaultKaptcha;
}
}
四、编写验证码vo
package com.example.securityzimug.config.auth.imagecode;
import java.time.LocalDateTime;
public class CaptchaCode {
/**
* 验证码
*/
private String code;
/**
* 过期时间
*/
private LocalDateTime expireTime;
public CaptchaCode(String code, int expireAfterSeconds){
this.code = code;
this.expireTime = LocalDateTime.now().plusSeconds(expireAfterSeconds);
}
/**
* 是否过期
* @return
*/
public boolean isExpired(){
return LocalDateTime.now().isAfter(expireTime);
}
public String getCode() {
return code;
}
}
五、编写控制器
package com.example.securityzimug.controller;
import com.example.securityzimug.config.auth.imagecode.CaptchaCode;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.image.BufferedImage;
import java.io.IOException;
@RestController
public class CaptchaController {
@Resource
DefaultKaptcha captchaProducer;
@RequestMapping(value="/kaptcha",method = RequestMethod.GET)
public void kaptcha(HttpSession session, HttpServletResponse response) throws IOException {
response.setDateHeader("Expires", 0);
response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
response.addHeader("Cache-Control", "post-check=0, pre-check=0");
response.setHeader("Pragma", "no-cache");
response.setContentType("image/jpeg");
String capText = captchaProducer.createText();
session.setAttribute(MyContants.CAPTCHA_SESSION_KEY,new CaptchaCode(capText,60));
try(ServletOutputStream out = response.getOutputStream()){
BufferedImage bufferedImage = captchaProducer.createImage(capText);
ImageIO.write(bufferedImage,"jpg",out);
out.flush();
}
}
}
这里用到了一个常量类,到时候做验证码判断时用的比较多:
package com.example.securityzimug.utils;
public class MyContants {
public static final String CAPTCHA_SESSION_KEY = "captcha_key";
public static final String SMS_SESSION_KEY = "sms_key";
}
六、开放验证码接口权限
七、修改登录页
<form action="/login" method="post">
<span>用户名称</span><input type="text" name="uname" id="username"/> <br>
<span>用户密码</span><input type="password" name="pword" id="password"/> <br>
<span>验证码</span><input type="text" name="captchaCode" id="captchaCode"/>
<img src="/kaptcha" id="kaptcha" width="110px" height="40px"/> <br>
<input type="button" onclick="login()" value="登陆">
<!-- <input type="submit" value="登陆">-->
<label><input type="checkbox" name="remember-me" id="remember-me"/>记住密码</label>
</form>
编写点击验证码刷新
window.onload = function () {
var kaptchaImg = document.getElementById("kaptcha");
kaptchaImg.onclick = function () {
kaptchaImg.src = "/kaptcha?" + Math.floor(Math.random() * 100)
}
};
到这里我们已经实现了验证码的刷新了:
八、编写验证码过滤器
package com.example.securityzimug.config.auth.imagecode;
import com.example.securityzimug.config.auth.MyAuthenticationFailureHandler;
import com.example.securityzimug.utils.MyContants;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.session.SessionAuthenticationException;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author baikunlong
* @date 2020/9/23 16:17
*/
@Component
public class CaptchaCodeFilter extends OncePerRequestFilter {
@Resource
MyAuthenticationFailureHandler myAuthenticationFailureHandler;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
if("/login".equals(request.getRequestURI())&&request.getMethod().equalsIgnoreCase("post")){
try {
validate(request);
} catch (AuthenticationException e) {
//交给自定义处理器处理
myAuthenticationFailureHandler.onAuthenticationFailure(request,httpServletResponse,e);
//直接返回,过滤器链不再往下执行
return;
}
}
filterChain.doFilter(request,httpServletResponse);
}
private void validate(HttpServletRequest request) {
//用户输入的验证码
String captchaInRequest = request.getParameter("captchaCode");
//session里的验证码对象
CaptchaCode captchaInSession = (CaptchaCode) request.getSession().getAttribute(MyContants.CAPTCHA_SESSION_KEY);
if(StringUtils.isEmpty(captchaInRequest)){
throw new SessionAuthenticationException("验证码不能为空");
}
if(captchaInSession==null){
throw new SessionAuthenticationException("验证码不存在");
}
if(captchaInSession.isExpired()){
request.getSession().removeAttribute(MyContants.CAPTCHA_SESSION_KEY);
throw new SessionAuthenticationException("验证码已经过期");
}
if(!captchaInSession.getCode().equalsIgnoreCase(captchaInRequest)){
throw new SessionAuthenticationException("验证码错误");
}
}
}
然后在自定义的那个失败处理器里处理下验证码错误的信息:
然后在配置类里注入过滤器:
@Resource
CaptchaCodeFilter captchaCodeFilter;
然后配置过滤器执行顺序:
//配置验证码过滤器执行时间,设置在用户名密码校验之前
http.addFilterBefore(captchaCodeFilter, UsernamePasswordAuthenticationFilter.class);
最后在登录页面加入验证码的提交就行了:
function login() {
var username = $("#username").val();
var password = $("#password").val();
var captchaCode = $("#captchaCode").val();
var rememberMe = $("#remember-me").is(":checked");
if (username === "" || password === "") {
alert('用户名或密码不能为空');
return;
}
$.ajax({
type: "POST",
url: "/login",
data: {
"uname": username,
"pword": password,
"captchaCode": captchaCode,
"remember-me-new": rememberMe
},
success: function (json) {
if(json.isok){
location.href = json.data;
}else{
alert(json.message)
}
},
error: function (e) {
console.log(e.responseText);
}
});
}
还没有评论,来说两句吧...