02.实现图形验证码
Posted fly-book
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了02.实现图形验证码相关的知识,希望对你有一定的参考价值。
实现图形验证码
使用过滤器实现图形验证码
使用kaptcha验证码
<!--验证码组件-->
<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
<version>2.3.2</version>
</dependency>
/**
* 自定义身份验证失败处理程序
*/
public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException {
response.setStatus(HttpStatus.UNAUTHORIZED.value());
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write("{"error_code":"401","name":""+e.getClass()+"","message":""+e.getMessage()+""}");
}
}
public class VerificationCodeException extends AuthenticationException {
public VerificationCodeException(){
super("验证码校验失败");
}
}
/**
* 验证码过滤器
* OncePerRequestFilter 确保一次请求只会通过一次该过滤器
* 核对session中保存的验证码与用户提交的验证码是否一致
* // /auth/form 登录请求才校验验证码
* {@link WebSecurityConfig}
*/
public class VerificationCodeFilter extends OncePerRequestFilter {
private AuthenticationFailureHandler handler = new MyAuthenticationFailureHandler();
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
if ("/auth/form".equals(request.getRequestURI())){
try {
verificationCode(request);
filterChain.doFilter(request,response);
}catch (VerificationCodeException e){
handler.onAuthenticationFailure(request,response,e);
}
}else {
filterChain.doFilter(request,response);
}
}
public void verificationCode(HttpServletRequest request) throws VerificationCodeException {
String requestCode = request.getParameter("captcha");
HttpSession session = request.getSession();
String saveCode = (String) session.getAttribute("captcha");
if (!StringUtils.isEmpty(saveCode)){
//随手清除验证码
session.removeAttribute("captcha");
}
//校验不通过,抛出异常
if (StringUtils.isEmpty(requestCode)||StringUtils.isEmpty(saveCode)||!requestCode.equals(saveCode)){
throw new VerificationCodeException();
}
}
}
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Bean
public AuthenticationProvider authenticationProvider(){
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(userDetailsService());
authenticationProvider.setPasswordEncoder(passwordEncoder());
return authenticationProvider;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/api/**").hasRole("ADMIN")
.antMatchers("/user/api/**").hasRole("USER")
.antMatchers("/app/api/**", "/captcha","/captchaLogin.html").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().loginPage("/captchaLogin.html")
.loginProcessingUrl("/auth/form")
.successHandler(new AuthenticationSuccessHandler() {
@Override
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
httpServletResponse.setContentType("application/json;charset=UTF-8");
httpServletResponse.getWriter().write("{"error_code":"0","message":"欢迎登陆"}");
}
})
.failureHandler(new MyAuthenticationFailureHandler())
// .and().sessionManagement().maximumSessions(1)
// .and().and().csrf().disable();
.and().csrf().disable();
http.addFilterBefore(new VerificationCodeFilter(), UsernamePasswordAuthenticationFilter.class);
}
@Bean
public UserDetailsService userDetailsService(){
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
manager.createUser(User.withUsername("user").password(new BCryptPasswordEncoder().encode("123")).roles("USER").build());
manager.createUser(User.withUsername("admin").password(new BCryptPasswordEncoder().encode("123")).roles("ADMIN").build());
return manager;
}
}
测试
@Controller
@SpringBootApplication(scanBasePackages = "com.security.config.captchaConfig")
public class Captchabootstrap {
public static void main(String[] args) {
SpringApplication.run(Captchabootstrap.class);
}
@Autowired
private Producer captchaProducer;
@Bean
public Producer captcha(){
Properties properties = new Properties();
properties.setProperty("kaptcha.image.width","150");
properties.setProperty("kaptcha.image.height","150");
//字符集
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;
}
@GetMapping("/captcha")
public void getCaptcha(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.setContentType("image/jpeg");
String capText = captchaProducer.createText();
request.getSession().setAttribute("captcha",capText);
BufferedImage bi = captchaProducer.createImage(capText);
ServletOutputStream out = response.getOutputStream();
ImageIO.write(bi,"jpg",out);
try {
out.flush();
} finally {
out.close();
}
}
@GetMapping("/index")
@ResponseBody
public String index(){
return "index";
}
@GetMapping("/admin/api")
public String admin(){
return "hello,admin";
}
@GetMapping("/user/api")
public String user(){
return "hello,user";
}
@GetMapping("/app/api")
public String app(){
return "hello,app";
}
}
<body>
<h1>login</h1>
<div>
username:<input id="username" type="text" name="username"><hr>
password:<input id="password" type="password" name="password"><hr>
<div style="display:flex;">
<input type="text" name="captcha" id="captcha">
<img src="/captcha" height="50px" width="150px" style="" alt="">
</div>
<button onclick="submit()">submit</button>
</div>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script>
function submit(){
var username = $('#username').val();
var password = $('#password').val();
var captcha = $('#captcha').val();
$.post("/auth/form",{username:username,password:password,captcha:captcha},function (res) {
if (res.error_code=='0'){
window.location.href="http://localhost:8080/index"
}
})
}
</script>
</body>
使用自定义认证实现图形验证码
public class MyWebAuthenticationDetails extends WebAuthenticationDetails {
private boolean imageCodeIsRight;
public boolean getImageCodeIsRight(){
return imageCodeIsRight;
}
public MyWebAuthenticationDetails(HttpServletRequest request) {
super(request);
String imageCode = request.getParameter("captcha");
HttpSession session = request.getSession();
String saveImageCode = (String)session.getAttribute("captcha");
if (!StringUtils.isEmpty(saveImageCode)){
session.removeAttribute("captcha");
if (!StringUtils.isEmpty(imageCode)&&imageCode.equals(saveImageCode)){
this.imageCodeIsRight = true;
}
}
}
}
@Component
public class MyWebAuthenticationDetailsSource implements AuthenticationDetailsSource<HttpServletRequest, WebAuthenticationDetails> {
@Override
public WebAuthenticationDetails buildDetails(HttpServletRequest request) {
return new MyWebAuthenticationDetails(request);
}
}
public class MyAuthenticationProvider extends DaoAuthenticationProvider {
public MyAuthenticationProvider(UserDetailsService userDetailsService, PasswordEncoder passwordEncoder) {
setUserDetailsService(userDetailsService);
setPasswordEncoder(passwordEncoder);
}
/**
* 其他身份验证检查
* @param userDetails
* @param authentication
* @throws AuthenticationException
*/
@Override
protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
MyWebAuthenticationDetails details = (MyWebAuthenticationDetails) authentication.getDetails();
if (!details.getImageCodeIsRight()){
throw new VerificationCodeException();
}
super.additionalAuthenticationChecks(userDetails, authentication);
}
}
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private AuthenticationDetailsSource<HttpServletRequest, WebAuthenticationDetails> myWebAuthenticationDetailsAuthenticationDetailsSource;
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Bean
public MyAuthenticationProvider myAuthenticationProvider(){
return new MyAuthenticationProvider(userDetailsService(),passwordEncoder());
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(myAuthenticationProvider());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/api/**").hasRole("ADMIN")
.antMatchers("/user/api/**").hasRole("USER")
.antMatchers("/app/api/**", "/captcha","/captchaLogin.html").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.authenticationDetailsSource(myWebAuthenticationDetailsAuthenticationDetailsSource)
.loginPage("/captchaLogin.html")
.loginProcessingUrl("/auth/form")
.successHandler(new AuthenticationSuccessHandler() {
@Override
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
httpServletResponse.setContentType("application/json;charset=UTF-8");
httpServletResponse.getWriter().write("{"error_code":"0","message":"欢迎登陆"}");
}
})
.failureHandler(new MyAuthenticationFailureHandler())
.and().csrf().disable();
}
@Bean
public UserDetailsService userDetailsService(){
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
manager.createUser(User.withUsername("user").password(new BCryptPasswordEncoder().encode("123")).roles("USER").build());
manager.createUser(User.withUsername("admin").password(new BCryptPasswordEncoder().encode("123")).roles("ADMIN").build());
return manager;
}
}
以上是关于02.实现图形验证码的主要内容,如果未能解决你的问题,请参考以下文章