springsecurity集成kaptcha功能

前端代码

本次采用简单的html静态页面作为演示,也可结合vue前后端分离开发,复制就可运行测试

项目目录

登录界面




    
    Title
    


账号:
密码:
验证码:
点击更换
记住我:

登录成功




    
    Title


成功退出

后端代码

springsecurity集成kaptcha功能_第1张图片

pom

    
        
        
            org.springframework.boot
            spring-boot-starter-web
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
        
        
        
            com.github.penggle
            kaptcha
            2.3.2
        
        
        
            org.springframework.boot
            spring-boot-starter-security
        
        
            org.springframework.security
            spring-security-test
            test
        
        
        
            mysql
            mysql-connector-java
        
        
            org.springframework.boot
            spring-boot-starter-jdbc
        
    

配置类

kaptcha配置类用于生成验证码格式

import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Properties;



@Configuration
public class KaptchaConfiguration {
    @Bean
    public DefaultKaptcha getDefaultKaptcha() {
        com.google.code.kaptcha.impl.DefaultKaptcha defaultKaptcha = new com.google.code.kaptcha.impl.DefaultKaptcha();
        Properties properties = new Properties();

        properties.put("kaptcha.textproducer.char.string", "0123456789");
        properties.put("kaptcha.border", "no");
        properties.put("kaptcha.textproducer.font.color", "black");
        properties.put("kaptcha.textproducer.char.space", "5");
        properties.put("kaptcha.textproducer.char.length","4");
        properties.put("kaptcha.image.height","34");
        properties.put("kaptcha.textproducer.font.size","30");
        properties.setProperty("kaptcha.image.width", "164");
        properties.setProperty("kaptcha.image.height", "64");
        properties.put("kaptcha.noise.impl","com.google.code.kaptcha.impl.NoNoise");

        Config config = new Config(properties);
        defaultKaptcha.setConfig(config);

        return defaultKaptcha;
    }

}

springsecurity

import com.sfy.kapcha.filter.CodeFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import javax.sql.DataSource;


@Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private DataSource dataSource;
    @Autowired
    PersistentTokenRepository persistentTokenRepository;

    @Bean
    public PasswordEncoder getPw(){
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 基于内存存储的多用户
        auth.inMemoryAuthentication().withUser("admin").password(getPw().encode("123")).roles("root");
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        // 忽略静态请求
        web.ignoring().antMatchers("/img/**", "/js/**");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin()
                //当发现是login时认为是登录,必须和表单提供的地址一致去执行UserDetailsServiceImpl
                .loginProcessingUrl("/login")
                //自定义登录界面
                .loginPage("/login.html")
                .successForwardUrl("/toMain")
                .permitAll()
                .and()
                .addFilterBefore(new CodeFilter(), UsernamePasswordAuthenticationFilter.class);

        //认证授权
        http.authorizeRequests()
                .antMatchers("/kaptcha").permitAll()
                //登录放行不需要认证
                .antMatchers("/login.html").permitAll()
                //所有请求都被拦截类似于mvc必须登录后访问
                .anyRequest().authenticated();
        //关闭csrf防护
        http.csrf().disable();

        //退出登录
        http.logout()
                .logoutSuccessUrl("/login.html");

        //记住我
        http.rememberMe().tokenValiditySeconds(60);
    }

    @Bean
    public AuthenticationManager authenticationManagerBean()
            throws Exception {
        return super.authenticationManagerBean();
    }

    @Bean
    public PersistentTokenRepository getPersistentTokenRepository(){
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
        jdbcTokenRepository.setDataSource(dataSource);
        //第一次启动时建表,第二次使用时注释掉
        //jdbcTokenRepository.setCreateTableOnStartup(true);
        return jdbcTokenRepository;
    }
}

controller

kaptcha

import com.google.code.kaptcha.Constants;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.image.BufferedImage;

/**
 * @Author: sfy
 * @Date: 2024/1/18 11:13
 */

@RestController
public class KapchaController {
    @Autowired
    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();
        }
    }

}

springsecurity集成kaptcha功能_第2张图片

 login进行简单的页面重定向(要用Controller)

@Controller
public class LoginController {

    @RequestMapping("/toMain")
    public String toMain(){
        return "redirect:main.html";
    }

}

filter

用于检测图像验证码的正确性,只有当验证码正确时,过滤器链才会走到springsecurity的检测

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);
    }

}

 数据库

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/security?serverTimezone=GMT%2B8
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: root
  main:
    allow-circular-references: true #开始支持spring循环依赖

当第一次执行项目时,会在库中生成表数据 

你可能感兴趣的:(java)