利用kaptcha生成验证码,并转化为base64回传给前台
pom.xml
<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
<version>2.3.2</version>
</dependency>
KaptchaConfig配置文件
@Configuration
public class KaptchaConfig {
@Bean
public 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;
}
}
controller前端获取base64接口,可将图片从存储在session转为存在redis,可实现设置过期时间
@GetMapping("/vc.jpg")
public String getVerifyCode(HttpSession session) throws IOException {
//1.生成验证码
String text = producer.createText();
//2.放入 session redis 实现
session.setAttribute("kaptcha", text);
//3.生成图片
BufferedImage bi = producer.createImage(text);
FastByteArrayOutputStream fos = new FastByteArrayOutputStream();
ImageIO.write(bi, "jpg", fos);
//4.返回 base64
return Base64.encodeBase64String(fos.toByteArray());
}
以下为整合springsecurity后,loginfilter过滤器
public class LoginKaptchaFilter extends UsernamePasswordAuthenticationFilter {
private static final String SPRING_SECURITY_FORM_KAPTCHA_KEY = "kaptcha";
private String kaptchaParamter = SPRING_SECURITY_FORM_KAPTCHA_KEY;
public String getKaptchaParamter() {
return kaptchaParamter;
}
public void setKaptchaParamter(String kaptchaParamter) {
this.kaptchaParamter = kaptchaParamter;
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
if (!request.getMethod().equals("POST")) {
throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
}
try {
Map<String,String> map = new ObjectMapper().readValue(request.getInputStream(), Map.class);
String kaptcha = map.get(getKaptchaParamter());
String username = map.get(getUsernameParameter());
String password = map.get(getPasswordParameter());
String sessionVerifyCode = (String) request.getSession().getAttribute("kaptcha");
if(kaptcha.equalsIgnoreCase(sessionVerifyCode)){
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
// Allow subclasses to set the "details" property
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
} catch (IOException e) {
e.printStackTrace();
}
throw new KaptchaNotMatchException("验证码不匹配!");
}
}
自定义认证异常类,用来替换SecurityConfig中的configure(HttpSecurity http)中的异常处理
//自定义验证码认证异常
public class KaptchaNotMatchException extends AuthenticationException {
public KaptchaNotMatchException(String msg) {
super(msg);
}
public KaptchaNotMatchException(String msg, Throwable cause) {
super(msg, cause);
}
}
SecurityConfig
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public UserDetailsService myUserDetailsService(){
InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();
inMemoryUserDetailsManager.createUser(User.withUsername("root").password("{noop}123").roles("admin").build());
return inMemoryUserDetailsManager;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(myUserDetailsService());
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.mvcMatchers("/vc.jpg").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.exceptionHandling()
.authenticationEntryPoint(new AuthenticationEntryPoint() {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
response.setStatus(HttpStatus.UNAUTHORIZED.value());
response.setContentType("application/json;charset=UTF-8");
response.getWriter().println("请先认证!");
}
})
.and()
.csrf().disable();
http.addFilterAt(loginKaptchaFilter(), UsernamePasswordAuthenticationFilter.class);
}
@Bean
public LoginKaptchaFilter loginKaptchaFilter(){
LoginKaptchaFilter loginKaptchaFilter = new LoginKaptchaFilter();
loginKaptchaFilter.setFilterProcessesUrl("/login");
try {
loginKaptchaFilter.setAuthenticationManager(authenticationManagerBean());
loginKaptchaFilter.setUsernameParameter("username");
loginKaptchaFilter.setPasswordParameter("password");
loginKaptchaFilter.setKaptchaParamter("kap");
loginKaptchaFilter.setAuthenticationSuccessHandler((req,resp,auth)->{
HashMap<Object, Object> map = new HashMap<>();
map.put("msg",auth.getAuthorities()+"用户已登录");
resp.setContentType("application/json;charset=UTF-8");
String s = new ObjectMapper().writeValueAsString(map);
resp.getWriter().println(s);
});
loginKaptchaFilter.setAuthenticationFailureHandler((req,resp,exception)->{
HashMap<Object, Object> map = new HashMap<>();
map.put("msg","登陆失败"+exception.getMessage());
resp.setContentType("application/json;charset=UTF-8");
ObjectMapper mapper = new ObjectMapper();
String s = mapper.writeValueAsString(map);
resp.getWriter().println(s);
});
} catch (Exception e) {
e.printStackTrace();
}
return loginKaptchaFilter;
}
}