SpringBoot 集成 SpringSecurity 验证码验证登录
-
主要依赖
<!-- 验证码生成的库 --> <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-security</artifactId> </dependency>
-
生成验证码的接口
@RestController public class KaptchaController { @Autowired private DefaultKaptcha defaultKaptcha; @GetMapping("/kaptcha") public void getKaptchaImage(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpSession session = request.getSession(); 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 = defaultKaptcha.createText(); // 验证码放入session session.setAttribute(Constants.KAPTCHA_SESSION_KEY, capText); BufferedImage bi = defaultKaptcha.createImage(capText); ServletOutputStream out = response.getOutputStream(); ImageIO.write(bi, "jpg", out); try { out.flush(); } finally { out.close(); } } }
-
filter进行拦截
public class CodeFilter extends HttpFilter { @Override protected void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws IOException, ServletException { String uri = req.getServletPath(); if (uri.equals("/login") && req.getMethod().equalsIgnoreCase("post")) { // 服务端生成的验证码数据 String sessionCode = req.getSession().getAttribute(Constants.KAPTCHA_SESSION_KEY).toString(); System.out.println("正确的验证码: " + sessionCode); // 用户输入的验证码数据 String formCode = req.getParameter("code").trim(); System.out.println("用户输入的验证码: " + formCode); if (StringUtils.isEmpty(formCode)) { throw new RuntimeException("验证码不能为空"); } if (sessionCode.equals(formCode)) { System.out.println("验证通过"); } else { throw new AuthenticationServiceException("验证码输入不正确"); } } chain.doFilter(req, res); } }
-
Security配置类
@Configuration @EnableWebSecurity public class KaptchaConfig extends WebSecurityConfigurerAdapter { // 加密方式 private final PasswordEncoder ENCODER = new BCryptPasswordEncoder(); @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // 基于内存存储的多用户 auth.inMemoryAuthentication().withUser("root").password(ENCODER.encode("root")).roles("root").and() .withUser("admin").password(ENCODER.encode("admin")).roles("admin"); } @Override public void configure(WebSecurity web) throws Exception { // 忽略静态请求 web.ignoring().antMatchers("/img/**", "/js/**"); } @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/kaptcha").permitAll() // 所有请求都需要验证 .anyRequest().authenticated() .and() // 登录页面 .formLogin().loginPage("/in.html") // 登录信息请求路径 .loginProcessingUrl("/login") // 登录成功跳转的路径 .defaultSuccessUrl("/") // ******登录失败跳转的路径****** .failureUrl("/login.html?error") //permitAll 给没登录的 用户可以访问这个地址的权限 .permitAll() .and() // 添加一个前置Filter .addFilterBefore(new CodeFilter(), UsernamePasswordAuthenticationFilter.class) .csrf() //关闭csrf防护 .disable() ; } /** * @return 返回加密方式 */ @Bean public PasswordEncoder passwordEncoder() { return ENCODER; } /** * Kaptcha配置 * @return */ @Bean public DefaultKaptcha getDefaultKaptcha(){ DefaultKaptcha captchaProducer = new DefaultKaptcha(); 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.image.width", "310"); properties.setProperty("kaptcha.image.height", "240"); properties.setProperty("kaptcha.textproducer.font.size", "150"); properties.setProperty("kaptcha.session.key", "code"); properties.setProperty("kaptcha.textproducer.char.length", "4"); properties.setProperty("kaptcha.textproducer.char.string", "0123456789"); properties.setProperty("kaptcha.obscurificator.impl", "com.google.code.kaptcha.impl.ShadowGimpy"); properties.setProperty("kaptcha.textproducer.font.names", "宋体,楷体,微软雅黑"); Config config = new Config(properties); captchaProducer.setConfig(config); return captchaProducer; } }
注:Kaptcha相关配置
onstant 描述 默认值 aptcha.border 图片边框,合法值:yes , no yes aptcha.border.color 边框颜色,合法值: r,g,b (and optional alpha) 或者 white,black,blue. black aptcha.image.width 图片宽 200 aptcha.image.height 图片高 50 aptcha.producer.impl 图片实现类 com.google.code.kaptcha.impl.DefaultKaptcha aptcha.textproducer.impl 文本实现类 com.google.code.kaptcha.text.impl.DefaultTextCreator aptcha.textproducer.char.string 文本集合,验证码值从此集合中获取 abcde2345678gfynmnpwx aptcha.textproducer.char.length 验证码长度 5 aptcha.textproducer.font.names 字体 Arial, Courier aptcha.textproducer.font.size 字体大小 40px. aptcha.textproducer.font.color 字体颜色,合法值: r,g,b 或者 white,black,blue. black aptcha.textproducer.char.space 文字间隔 2 aptcha.noise.impl 干扰实现类 com.google.code.kaptcha.impl.DefaultNoise aptcha.noise.color 干扰 颜色,合法值: r,g,b 或者 white,black,blue. black aptcha.obscurificator.impl 图片样式:
水纹 com.google.code.kaptcha.impl.WaterRipple
鱼眼 com.google.code.kaptcha.impl.FishEyeGimpy
阴影 com.google.code.kaptcha.impl.ShadowGimpycom.google.code.kaptcha.impl.WaterRipple aptcha.background.impl 背景实现类 com.google.code.kaptcha.impl.DefaultBackground aptcha.background.clear.from 背景颜色渐变,开始颜色 light grey aptcha.background.clear.to 背景颜色渐变, 结束颜色 white aptcha.word.impl 文字渲染器 com.google.code.kaptcha.text.impl.DefaultWordRenderer aptcha.session.key session key KAPTCHA_SESSION_KEY aptcha.session.date session date KAPTCHA_SESSION_DATE -
登录页
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登录</title> </head> <style> .codeClass{ width: 150px; height: 100px; } </style> <body> <!-- action = 登录信息请求路径 --> <form action="/login" method="post"> <label for="username">账号</label><input id="username" type="text" name="username"><br> <label for="password">密码</label><input id="password" type="password" name="password"><br> <p><input type='checkbox' name='remember-me'/> 记住我 </p> <label for="code">验证码</label><input id="code" type="text" name="code"><img class="codeClass" src="/kaptcha"> <input type="submit" value="登录"/> </form> </body> </html>