Spring Security添加验证码的两种方式小结

网友投稿 350 2022-09-23


Spring Security添加验证码的两种方式小结

目录一、自定义认证逻辑二、自定义过滤器总结

一、自定义认证逻辑

生成验证码工具

com.github.penggle

kaptcha

2.3.2

添加Kaptcha配置

@Configuration

public class KaptchaConfig {

@Bean

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;

}

}

生成验证码文本,放入HttpSession中

根据验证码文本生成图片 通过IO流写出到前端。

@RestController

public class LoginController {

@Autowired

Producer producer;

@GetMapping("/vc.jpg")

public void getVerifyCode(HttpServletResponse resp, HttpSession session) throws IOException {

resp.setContentType("image/jpeg");

String text = producer.createText();

session.setAttribute("kaptchaQtYbZr", text);

BufferedImage image = producer.createImage(text);

try(ServletOutputStream out = resp.getOutputStream()) {

ImageIO.write(image, "jpg", out);

}

}

@RequestMapping("/index")

public String index() {

return "login success";

}

@RequestMapping("/hello")

public String hello() {

return "hello spring security";

}

}

form表单




Spring Security添加验证码的两种方式小结

验证码图片地址为我们在Controller中定义的验证码接口地址。

身份认证是AuthenticationProvider的authenticate方法完成,因此验证码可以在此之前完成:

public class KaptchaAuthenticationProvider extends DaoAuthenticationProvider {

@Override

public 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 && sessionKaptcha != null && kaptcha.equalsIgnoreCase(sessionKaptcha)) {

return super.authenticate(authentication);

}

throw new AuthenticationServiceException("验证码输入错误");

}

}

配置AuthenticationManager:

@Configuration

public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Bean

AuthenticationProvider kaptchaAuthenticationProvider() {

InMemoryUserDetailsManager users = new InMemoryUserDetailsManager(User.builder()

.username("xiepanapn").password("{noop}123").roles("admin").build());

KaptchaAuthenticationProvider provider = new KaptchaAuthenticationProvider();

provider.setUserDetailsService(users);

return provider;

}

@Override

@Bean

public AuthenticationManager authenticationManagerBean() throws Exception {

ProviderManager manager = new ProviderManager(kaptchaAuthenticationProvider());

return manager;

}

@Override

protected void configure(HttpSecurity http) throws Exception {

http.authorizeRequests()

.antMatchers("/vc.jpg").permitAll()

.anyRequest().authenticated()

.and()

.formLogin()

.loginPage("/mylogin.html")

.loginProcessingUrl("/doLogin")

.defaultSuccessUrl("/index.html")

.failureForwardUrl("/mylogin.html")

.usernameParameter("uname")

.passwordParameter("passwd")

.permitAll()

.and()

.csrf().disable();

}

}

配置UserDetailsService提供的数据源

提供AuthenticationProvider实例并配置UserDetailsService

重写authenticationManagerBean方法提供一个自己的ProviderManager并自定义AuthenticationManager实例。

二、自定义过滤器

LoginFilter继承UsernamePasswordAuthenticationFilter 重写attemptAuthentication方法:

public class LoginFilter extends UsernamePasswordAuthenticationFilter {

@Override

public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {

if (!request.getMethod().equals("POST")) {

throw new AuthenticationServiceException(

"Authentication method not supported: " + request.getMethod());

}

String kaptcha = request.getParameter("kaptcha");

String sessionKaptcha = (String) request.getSession().getAttribute("kaptcha");

if (!StringUtils.isEmpty(kaptcha) && !StringUtils.isEmpty(sessionKaptcha) && kaptcha.equalsIgnoreCase(sessionKaptcha)) {

return super.attemptAuthentication(request, response);

}

throw new AuthenticationServiceException("验证码输入错误");

}

}

在SecurityConfig中配置LoginFilter

@Configuration

public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Override

protected void configure(AuthenticationManagerBuilder auth)

throws Exception {

auth.inMemoryAuthentication()

.withUser("javaboy")

.password("{noop}123")

.roles("admin");

}

@Override

@Bean

public AuthenticationManager authenticationManagerBean()

throws Exception {

return super.authenticationManagerBean();

}

@Bean

LoginFilter loginFilter() throws Exception {

LoginFilter loginFilter = new LoginFilter();

loginFilter.setFilterProcessesUrl("/doLogin");

loginFilter.setAuthenticationManager(authenticationManagerBean());

loginFilter.setAuthenticationSuccessHandler(new SimpleUrlAuthenticationSuccessHandler("/hello"));

loginFilter.setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler("/mylogin.html"));

return loginFilter;

}

@Override

protected void configure(HttpSecurity http) throws Exception {

http.authorizeRequests()

.antMatchers("/vc.jpg").permitAll()

.anyRequest().authenticated()

.and()

.formLogin()

.loginPage("/mylogin.html")

.permitAll()

.and()

.csrf().disable();

http.addFilterAt(loginFilter(),

UsernamePasswordAuthenticationFilter.class);

}

}

显然第二种比较简单

总结


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

上一篇:BGP的反射器和联盟(bgp协议中部署路由反射器和联盟的目的)
下一篇:假装网络工程师12——ospf中的特殊区域及6,7类lsa详解(下图所示的网络中,采用了ospf)
相关文章

 发表评论

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