SpringSecurity实现图形验证码功能实例代码

网友投稿 283 2023-01-20


SpringSecurity实现图形验证码功能实例代码

Spring Security

Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。

本文重点给大家介绍SpringSecurity实现图形验证码功能,具体内容如下:

1.开发生成图形验证码接口

-> 封装ImageCode对象,来存放图片验证码的内容、图片以及有效时间

public class ImageCode {

private BufferedImage image;// 图片

private String code;// 验证码

private LocalDateTime expireTime;// 有效时间

public ImageCode(BufferedImage image, String code, int expireIn) {

this.image = image;

this.code = code;

// 出入一个秒数,自动转为时间,如过期时间为60s,这里的expireIn就是60,转换为当前时间上加上这个秒数

this.expireTime = LocalDateTime.now().plusSeconds(expireIn);

}

public ImageCode(BufferedImage image, String code, LocalDateTime expireTime) {

this.image = image;

this.code = code;

this.expireTime = expireTime;

}

public BufferedImage getImage() {

return image;

}

public void setImage(BufferedImage image) {

this.image = image;

}

public String getCode() {

return code;

}

public void setCode(String code) {

this.code = code;

}

public LocalDateTime getExpireTime() {

return expireTime;

}

public void setExpireTime(LocalDateTime expireTime) {

this.expireTime = expireTime;

}

}

-> 写一个Controller用于生成图片和校验验证码

public class ValidateCodeController {

private static final String SESSION_KEY = "SESSION_KEY_IMAGE_CODE";

private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy();

@GetMapping("/code/image")

public void createCode(HttpServletRequest request, HttpServletResponse response) throws IOException {

// 根据随机数生成图片

ImageCode imageCode = createImageCode(request);

// 将随机数存到session中

sessionStrategy.setAttribute(new ServletWebRequest(request), SESSION_KEY, imageCode);

// 将生成的图片写到接口的响应中

ImageIO.write(imageCode.getImage(), "JPEG", response.getOutputStream());

}

private ImageCode createImageCode(HttpServletRequest request) {

// 图片的宽高(像素)

int width = 67;

int height = 23;

// 生成图片对象

BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

Graphics g = image.getGraphics();

// 生成随机条纹干扰

Random random = new Random();

g.setColor(getRandColor(200, 250));

g.fillRect(0, 0, width, height);

g.setFont(new Font("Times New Roman", Font.ITALIC, 20));

g.setColor(getRandColor(160, 200));

for (int i = 0; i < 155; i++) {

int x = random.nextInt(width);

int y = random.nextInt(height);

int xl = random.nextInt(12);

int yl = random.nextInt(12);

g.drawLine(x, y, xl, yl);

}

// 生成四位随机数

String sRand = "";

for (int i = 0; i < 4; i++) {

String rand = String.valueOf(random.nextInt(10));

sRand += rand;

g.setColor(new Color(20 + random.nextInt(110), 20 + random.nextInt(110), 20 + random.nextInt(110)));

g.drawString(rand, 13 * i + 6, 16);

}

g.dispose();

// 60秒有效

return new ImageCode(image, sRand, 60);

}

/**

* 生成随机背景条纹

* @param fc

* @param bc

* @return

*/

private Color getRandColor(int fc, int bc) {

Random random = new Random();

if(fc > 255) {

fc = 255;

}

if(bc > 255) {

bc = 255;

}

int r = fc + random.nextInt(bc - fc);

int g = fc + random.nextInt(bc - fc);

int b = fc + random.nextInt(bc - fc);

return new Color(r, g, b);

}

}

第一步:根据随机数生成图片

ImageCode imageCode = createImageCode(request);

第二步:将随机数存到session中

sessionStrategy.setAttribute(new ServletWebRequest(request), SESSION_KEY, imageCode);

第三步:将生成的图片写到接口的响应中

ImageIO.write(imageCode.getImage(), “JPEG”, response.getOutputStream());

-> 在静态页面中加入图片验证码的标签

-> 将接口请求地址配进认证

@Override

protected void configure(HttpSecurity http) throws Exception {

http.formLogin()

.loginPage("/authencation/require")

.loginProcessingUrl("/authentication/form")

.successHandler(imoocAuthenticationSuccessHandler)

.failureHandler(imoocAuthenticationFailureHandler)

.and()

.authorizeRequests()

.antMatchers("/authencation/require",

securityPropertis.getBrowserPropertis().getLoginPage(),

"/code/image").permitAll() // 加入"/code/image"地址

.anyRequest()

.authenticated()

.and()

.csrf().disable();

}

->启动服务器访问静态表单

如图所示:

2.在认证流程中加入图形验证码校验

-> 写一个filter进行拦截

public class ValidateCodeFilter extends OncePerRequestFilter{

private AuthenticationFailureHandler authenticationFailureHandler;

private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy();

@OvMvvfocxerride

protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)

throws ServletException, IOException {

//如果访问的是/authentication/form并且为post请求

if(StringUtils.equals("/authentication/form", request.getRequestURI())

&& StringUtils.equals(request.getMethod(), "post")) {

try {

// 验证图片验证码是否填写正确

validate(new ServletWebRequest(request));

} catch (ValidateCodeException e) {

// 抛出异常,并返回,不再访问资源

authenticationFailureHandler.onAuthenticationFailure(request, response, e);

return;

}

}

// 通过,执行后面的filter

filterChain.doFilter(request, response);

}

// 校验验证码的逻辑

private void validate(ServletWebRequest request) throws ServletRequestBindingException {

ImageCode codeInSession = (ImageCode) sessionStrategy.getAttribute(request, ValidateCodeController.SESSION_KEY);

String codeInRequest = ServletRequestUtils.getStringParameter(request.getRequest(), "imageCode");

if(StringUtils.isBlank(codeInRequest)) {

throw new ValidateCodeException("验证码的值不能为空");

}

if(codeInSession == null){

throw new ValidateCodeException("验证码不存在");

}

if(codeInSession.isExpried()) {

sessionStrategy.removeAttribute(request, ValidateCodeController.SESSION_KEY);

throw new ValidateCodeException("验证码已过期");

}

if(!StringUtils.equals(codeInSession.getCode(), codeInRequest)) {

throw new ValidateCodeException("验证码不匹配");

}

sessionStrategy.removeAttribute(request, ValidateCodeController.SESSION_KEY);

}

public AuthenticationFailureHandler getAuthenticationFailureHandler() {

return authenticationFailureHandler;

}

public void setAuthenticationFailureHandler(AuthenticationFailureHandler authenticationFailureHandler) {

this.authenticationFailureHandler = authenticationFailureHandler;

}

public SessionStrategy getSessionStrategy() {

return sessionStrategy;

}

public void setSessionStrategy(SessionStrategy sessionStrategy) {

this.sessionStrategy = sessionStrategy;

}

}

-> 配置再configure中,生效

@Override

protected void configure(HttpSecurity http) throws Exception {

// 声明filter

ValidateCodeFilter validateCodeFilter = new ValidateCodeFilter();

// 配置验证失败执行的handler

validateCodeFilter.setAuthenticationFailureHandler(imoocAuthenticationFailureHandler);

// 添加filter到认证流程

http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class)

.formLogin()

.loginPage("/authencation/require")

.loginProcessingUrl("/authentication/form")

.successHandler(imoocAuthenticationSuccessHandler)

.failureHandler(imoocAuthenticationFailureHandler)

.and()

.authorizeRequests()

.antMatchers("/authencation/require",

securityPropertis.getBrowserPropertis().getLoginPage(),

"/code/image").permitAll()

.anyRequest()

.authenticated()

.and()

.csrf().disable();

}

至此,图片验证码验证流程已经全部完成。

启动服务,进行测试即可。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Java垃圾回收之标记清除算法详解
下一篇:接口发布管理工具(管理接口的工具)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~