Spring Security自定义验证码登录
创始人
2024-04-10 10:17:54

本文内容来自王松老师的《深入浅出Spring Security》,自己在学习的时候为了加深理解顺手抄录的,有时候还会写一些自己的想法。

        验证码登录也是项目中一个常见的需求,但是Spring Security并未提供自动化配置方案。所以需要开发者自行定义。这里我们通过自定义认证逻辑实现添加登录验证码功能。

        生成验证码我们使用开源库kaptcha,首先引入kaptcha依赖,代码如下:

        com.github.pengglekaptcha2.3.2

        然后对kaptcha进行配置:

@Configuration
public class KaptchaConfig {@Beanpublic Producer kaptcha() {Properties properties = new Properties();properties.setProperty("kaptcha.image.width", "150");properties.setProperty("kaptcha.image.height", "50");properties.setProperty("kaptcha.textproducer.char.string", "0123456789");properties.setProperty("kaptcha.textproducer.char.length", "4");Config config = new Config(properties);DefaultKaptcha defaultKaptcha = new DefaultKaptcha();defaultKaptcha.setConfig(config);return defaultKaptcha;}
}

        配置一个Producer实例,只要配置一个生成的图片验证码的宽带、长度、生成字符、验证码的长度等信息。配置完成可以在Controller中定义一个验证码接口了:

    @Autowiredprivate Producer producer;@GetMapping("/vc.jpg")public void getVerifyCode(HttpServletResponse resp, HttpSession session) {resp.setContentType("image/jpeg");String text = producer.createText();session.setAttribute("kaptcha", text);BufferedImage image = producer.createImage(text);try (ServletOutputStream out = resp.getOutputStream()) {ImageIO.write(image, "jpg", out);} catch (Exception e) {e.printStackTrace();}}

        这个验证码接口中,主要做了两件事:

  • 生成验证码,并将文本存入HttpSession中
  • 根据验证码文本生成验证码图片,并通过IO流写出到前端。

        接下修改登录表单,加入验证码,代码如下:



自定义登录



登录




        在登录表单中增加一个输入验证码的输入框,验证码的图片地址就是我们在Controller中定义的验证码接口地址。

        接来下就是验证码的校验了。经过前面的学习,我们已经了解到身份认证实际上就是在AuthenticationProvider的authenticate方法中完成的。所以,验证码的校验,我们可以在该方法执行前进行,需要配置如下类:

/*** @author tlh* @date 2022/11/18 22:14*/
public class KaptchaAuthenticationProvider extends DaoAuthenticationProvider {@Overridepublic Authentication authenticate(Authentication authentication) throws AuthenticationException {HttpServletRequest req = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();String kaptcha = req.getParameter("kaptcha");String sessionKaptcha = (String) req.getSession().getAttribute("kaptcha");if (kaptcha != null && kaptcha.equalsIgnoreCase(sessionKaptcha)) {return super.authenticate(authentication);}throw new AuthenticationServiceException("验证码输入错误");}
}

        这里重写authenticate方法,在authenticate方法中从RequestContextHolder获取当前请求,进而取到验证码参数和存储在HttpSession中的验证码文本进行对比。比如通过的话就执行父类的authenticate方法,不通过的话就抛出异常。

        我们将我们定义的KaptchaAuthenticationProvider通过配置类放入Spring的IOC容器中去:

/*** @author tlh* @date 2022/11/18 21:22*/
@Configuration
public class KaptchaConfig {@Autowiredprivate UserDetailsService userDetailsService;@Beanpublic AuthenticationProvider getAuthenticationProvider() {KaptchaAuthenticationProvider kaptchaAuthenticationProvider = new KaptchaAuthenticationProvider();kaptchaAuthenticationProvider.setUserDetailsService(userDetailsService);return kaptchaAuthenticationProvider;}
}

        这里需要注意的是我们在创建AuthenticationProvider的是需要一个UserDetailsService,这里的UserDetailsService是我们在前面学习的通过MyBatis从数据库中加载用户信息的时候定义的,如果有疑惑的的伙伴可以在去回顾下。

/*** @author tlh* @date 2022/11/17 23:52*/
@Component
public class MyUserDetailsService implements UserDetailsService {@Autowiredprivate UserMapper userMapper;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {User user = userMapper.loadUserByUsername(username);if (user == null) {throw new UsernameNotFoundException("用户不存在");}user.setRoles(userMapper.getRolesByUid(user.getId()));return user;}
}

        最后在SecurityConfig中配置AuthenticationManager,代码如下:

/*** @author tlh* @date 2022/11/16 21:11*/
@Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate AuthenticationProvider authenticationProvider;@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests()//放行验证码生成接口.antMatchers("/vc.jpg").permitAll().anyRequest().authenticated().and().formLogin().loginPage("/login.html").loginProcessingUrl("/doLogin").successHandler(getAuthenticationSuccessHandler()).failureUrl("/login.html").usernameParameter("uname").passwordParameter("passwd").permitAll().and().csrf().disable();}@Bean@Overridepublic AuthenticationManager authenticationManagerBean() throws Exception {ProviderManager providerManager = new ProviderManager(authenticationProvider);return providerManager;}/*** 登录成功处理器** @return*/private AuthenticationSuccessHandler getAuthenticationSuccessHandler() {return new AuthenticationSuccessHandler() {@Overridepublic void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {response.setContentType("application/json;charset=utf-8");Map respMap = new HashMap<>(2);respMap.put("code", "200");respMap.put("msg", "登录成功");ObjectMapper objectMapper = new ObjectMapper();String jsonStr = objectMapper.writeValueAsString(respMap);response.getWriter().write(jsonStr);}};}
}

        另外需要注意,在configure(HttpSecurity)方法中给验证码接口配置放行:antMatchers("/vc.jpg").permitAll()。配置完成后,启动项目,浏览中输入:localhost:8080/login.html,就能看到如下图:

        此时,输入正确的用户名、密码以及验证码就可以成功登录。 

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...