当前位置:首页 > 实用技巧 >

如何输入图片验证码(图片数字验证码怎样才能正确输入)

来源:原点资讯(www.yd166.com)时间:2023-04-22 12:29:48作者:YD166手机阅读>>

在前面的几篇文章中,登录时都是使用用户名 密码进行登录的,但是在实际项目当中,登录时,还需要输入图形验证码。那如何在 Spring Security 现有的认证体系中,加入自己的认证逻辑呢?这就是本文的内容,本文会介绍两种实现方案,一是基于过滤器实现;二是基于认证器实现。

既然需要输入图形验证码,那先来生成验证码吧。

加入验证码依赖

<!--验证码生成器--> <dependency> <groupId>com.github.penggle</groupId> <artifactId>kaptcha</artifactId> <version>2.3.2</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>

Kaptcha 依赖是谷歌的验证码工具。

验证码配置

@Configuration public class KaptchaConfig { @Bean public DefaultKaptcha captchaProducer() { Properties properties = new Properties(); // 是否显示边框 properties.setProperty("kaptcha.border","yes"); // 边框颜色 properties.setProperty("kaptcha.border.color","105,179,90"); // 字体颜色 properties.setProperty("kaptcha.textproducer.font.color","blue"); // 字体大小 properties.setProperty("kaptcha.textproducer.font.size","35"); // 图片宽度 properties.setProperty("kaptcha.image.width","300"); // 图片高度 properties.setProperty("kaptcha.image.height","100"); // 文字个数 properties.setProperty("kaptcha.textproducer.char.length","4"); //文字大小 properties.setProperty("kaptcha.textproducer.font.size","100"); //文字随机字体 properties.setProperty("kaptcha.textproducer.font.names", "宋体"); //文字距离 properties.setProperty("kaptcha.textproducer.char.space","16"); //干扰线颜色 properties.setProperty("kaptcha.noise.color","blue"); // 文本内容 从设置字符中随机抽取 properties.setProperty("kaptcha.textproducer.char.string","0123456789"); DefaultKaptcha kaptcha = new DefaultKaptcha(); kaptcha.setConfig(new Config(properties)); return kaptcha; } }验证码接口

/** * 生成验证码 */ @GetMapping("/verify-code") public void getVerifyCode(HttpServletResponse resp, HttpSession session) throws IOException { resp.setContentType("image/jpeg"); // 生成图形校验码内容 String text = producer.createText(); // 将验证码内容存入HttpSession session.setAttribute("verify_code", text); // 生成图形校验码图片 BufferedImage image = producer.createImage(text); // 使用try-with-resources 方式,可以自动关闭流 try(ServletOutputStream out = resp.getOutputStream()) { // 将校验码图片信息输出到浏览器 ImageIO.write(image, "jpeg", out); } }

代码注释写的很清楚,就不过多的介绍。属于固定的配置,既然配置完了,那就看看生成的效果吧!

如何输入图片验证码,图片数字验证码怎样才能正确输入(1)

接下来就看看如何集成到 Spring Security 中的认证逻辑吧!

加入依赖

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>基于过滤器

编写自定义认证逻辑

这里继承的过滤器为 UsernamePasswordAuthenticationFilter,并重写attemptAuthentication方法。用户登录的用户名/密码是在 UsernamePasswordAuthenticationFilter 类中处理,那我们就继承这个类,增加对验证码的处理。当然也可以实现其他类型的过滤器,比如:GenericFilterBean、OncePerrequestFilter,不过处理起来会比继承UsernamePasswordAuthenticationFilter麻烦一点。

import org.springframework.security.authentication.AuthenticationServiceException; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.util.StringUtils; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; public class VerifyCodeFilter extends UsernamePasswordAuthenticationFilter { @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { // 需要是 POST 请求 if (!request.getMethod().equals("POST")) { throw new AuthenticationServiceException( "Authentication method not supported: " request.getMethod()); } // 获得请求验证码值 String code = request.getParameter("code"); HttpSession session = request.getSession(); // 获得 session 中的 验证码值 String sessionVerifyCode = (String) session.getAttribute("verify_code"); if (StringUtils.isEmpty(code)){ throw new AuthenticationServiceException("验证码不能为空!"); } if(StringUtils.isEmpty(sessionVerifyCode)){ throw new AuthenticationServiceException("请重新申请验证码!"); } if (!sessionVerifyCode.equalsIgnoreCase(code)) { throw new AuthenticationServiceException("验证码错误!"); } // 验证码验证成功,清除 session 中的验证码 session.removeAttribute("verify_code"); // 验证码验证成功,走原本父类认证逻辑 return super.attemptAuthentication(request, response); } }

代码逻辑很简单,验证验证码是否正确,正确则走父类原本逻辑,去验证用户名密码是否正确。 过滤器定义完成后,接下来就是用我们自定义的过滤器代替默认的 UsernamePasswordAuthenticationFilter。

  • SecurityConfig

import cn.cxyxj.study04.Authentication.config.MyAuthenticationFailureHandler; import cn.cxyxj.study04.Authentication.config.MyAuthenticationSuccessHandler; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.password.NoOpPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.provisioning.InMemoryUserDetailsManager; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; @Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Bean PasswordEncoder passwordEncoder() { return NoOpPasswordEncoder.getInstance(); } @Bean @Override protected UserDetailsService userDetailsService() { InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager(); manager.createUser(User.withUsername("cxyxj").password("123").roles("admin").build()); manager.createUser(User.withUsername("security").password("security").roles("user").build()); return manager; } @Override @Bean public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Override protected void configure(HttpSecurity http) throws Exception { // 用自定义的 VerifyCodeFilter 实例代替 UsernamePasswordAuthenticationFilter http.addFilterBefore(new VerifyCodeFilter(), UsernamePasswordAuthenticationFilter.class); http.authorizeRequests() //开启配置 // 验证码、登录接口放行 .antMatchers("/verify-code","/auth/login").permitAll() .anyRequest() //其他请求 .authenticated().and()//验证 表示其他请求需要登录才能访问 .csrf().disable(); // 禁用 csrf 保护 } @Bean VerifyCodeFilter loginFilter() throws Exception { VerifyCodeFilter verifyCodeFilter = new VerifyCodeFilter(); verifyCodeFilter.setFilterProcessesUrl("/auth/login"); verifyCodeFilter.setUsernameParameter("account"); verifyCodeFilter.setPasswordParameter("pwd"); verifyCodeFilter.setAuthenticationManager(authenticationManagerBean()); verifyCodeFilter.setAuthenticationSuccessHandler(new MyAuthenticationSuccessHandler()); verifyCodeFilter.setAuthenticationFailureHandler(new MyAuthenticationFailureHandler()); return verifyCodeFilter; } }

当我们替换了 UsernamePasswordAuthenticationFilter 之后,原本在 SecurityConfig#configure 方法中关于 form 表单的配置就会失效,那些失效的属性,都可以在配置 VerifyCodeFilter 实例的时候配置;还需要记得配置AuthenticationManager,否则启动时会报错。

  • MyAuthenticationFailureHandler

import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.LockedException; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; /** * 登录失败回调 */ public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler { @Override public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException { response.setContentType("application/json;charset=utf-8"); PrintWriter out = response.getWriter(); String msg = ""; if (e instanceof LockedException) { msg = "账户被锁定,请联系管理员!"; } else if (e instanceof BadCredentialsException) { msg = "用户名或者密码输入错误,请重新输入!"; } out.write(e.getMessage()); out.flush(); out.close(); } }

  • MyAuthenticationSuccessHandler

import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.security.core.Authentication; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; /** * 登录成功回调 */ public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler { @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { Object principal = authentication.getPrincipal(); response.setContentType("application/json;charset=utf-8"); PrintWriter out = response.getWriter(); out.write(new ObjectMapper().writeValueAsString(principal)); out.flush(); out.close(); } }

测试

  • 不传入验证码发起请求。

如何输入图片验证码,图片数字验证码怎样才能正确输入(2)

  • 请求获取验证码接口

如何输入图片验证码,图片数字验证码怎样才能正确输入(3)

  • 输入错误的验证码

如何输入图片验证码,图片数字验证码怎样才能正确输入(4)

首页 123下一页

栏目热文

高中语文议论文阅读答题技巧(高中议论文阅读答题技巧模板)

高中语文议论文阅读答题技巧(高中议论文阅读答题技巧模板)

议论文阅读理解也是高中语文考试中的一项知识点,此类论述类文本阅读的考察,通常以选择题的方式出现,虽然分数占比没有太高,但...

2023-04-22 12:21:29查看全文 >>

高中语文阅读答题技巧论证方法(高中语文阅读答题技巧全套选择题)

高中语文阅读答题技巧论证方法(高中语文阅读答题技巧全套选择题)

语文阅读题方法归类一、表达方式:记叙、描写、抒情、说明、议论二、表现手法:象征、对比、烘托、设置悬念、前后呼应、欲扬先抑...

2023-04-22 12:01:14查看全文 >>

高中语文阅读题顺序答题技巧(高中语文阅读题答题套路和方法)

高中语文阅读题顺序答题技巧(高中语文阅读题答题套路和方法)

语文阅读理解的答题方法1.文章体裁?此文是一篇。诗歌、小说、散文(抒情散文、叙事散文)、戏剧、记叙文、说明文、议论文2...

2023-04-22 12:14:07查看全文 >>

高中语文教资答题技巧全套(高中语文答题技巧全套 新高考)

高中语文教资答题技巧全套(高中语文答题技巧全套 新高考)

高中语文答题技巧全套!语文似乎并不难,但想要取得一个高分却很不容易。掌握一些答题技巧,可以更轻松更流畅的答题。本文总结的...

2023-04-22 12:07:57查看全文 >>

初中语文阅读答题技巧(初中语文阅读答题技巧及套路)

初中语文阅读答题技巧(初中语文阅读答题技巧及套路)

中考阅文阅读的重点之一是记叙文、散文知识。其实,对文章的整体感知十分重要。整体感知包括对文章主旨的理解,对文章线索的把握...

2023-04-22 12:00:35查看全文 >>

图形码正确输入方法(手机图形验证码怎么输入)

图形码正确输入方法(手机图形验证码怎么输入)

近日,有市民咨询,称想了解如何网上自助办理异地就医备案。对此,西安市未央区徐家湾街道办详细整理了步骤:首先,登录 西安市...

2023-04-22 11:57:05查看全文 >>

怎样正确输入图形验证码(怎样输入数字图形验证码)

怎样正确输入图形验证码(怎样输入数字图形验证码)

叮~叮~叮~【党员干部接待岗问答】又上线了保定市公安交警支队为深化车检改革新措施推出了车检网上预约、“交钥匙”服务需要车...

2023-04-22 12:02:10查看全文 >>

字母图形验证码怎么输入才正确(怎样正确输入图形验证码)

字母图形验证码怎么输入才正确(怎样正确输入图形验证码)

多年预约经验分享给大家。高手勿喷。1、定个闹钟。现在热门纪念币预约基本秒光,所以要在预约期的第一天准点参加,准点到什么程...

2023-04-22 12:17:38查看全文 >>

快速输入图形验证码(图形验证码怎么输入才正确)

快速输入图形验证码(图形验证码怎么输入才正确)

老年人学手机(197)不用打数字快速填写验证码请看演示视频,然后再详细看文字内容: 因为平常我们登录一些软件的时...

2023-04-22 12:28:44查看全文 >>

图形数字验证码怎么输入(图形验证码怎么输入才正确)

图形数字验证码怎么输入(图形验证码怎么输入才正确)

今天上午收到广东移动通讯信息说我账户余额不足,不足以扣月租(扣月租的时间是每个月10号,时间还没到,只是提醒)。我感觉...

2023-04-22 12:26:40查看全文 >>

文档排行