• SpringSecurity系列 - 12 自定义过滤器实现登录页面添加验证码的认证


    1. 传统Web项目开发添加认证验证码

    在这里插入图片描述

    01. 项目依赖
    
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-securityartifactId>
    dependency>
    
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-webartifactId>
    dependency>
    
    <dependency>
        <groupId>org.projectlombokgroupId>
        <artifactId>lombokartifactId>
        <optional>trueoptional>
    dependency>
    
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-testartifactId>
        <scope>testscope>
    dependency>
    
    
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-thymeleafartifactId>
    dependency>
    
    
    <dependency>
        <groupId>com.github.pengglegroupId>
        <artifactId>kaptchaartifactId>
        <version>2.3.2version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    02. 登录页面 login.html
    DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>用户登录title>
    head>
    <body>
    <h1>用户登录h1>
    <form method="post" th:action="@{/doLogin}">
        用户名: <input name="uname" type="text"> <br>
        密码: <input name="passwd" type="text"> <br>
        验证码: <input name="kaptcha" type="text"> <img alt="" th:src="@{/vc.jpg}"> <br>
        <input type="submit" value="登录">
    form>
    
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    03. 欢迎页面 index.html
    DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>系统主页title>
    head>
    <body>
    <h1>欢迎进入我的主页h1>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    04. 配置访问页面的控制器
    @Configuration
    public class MvcConfig implements WebMvcConfigurer {
    
        @Override
        public void addViewControllers(ViewControllerRegistry registry) {
            registry.addViewController("/index.html").setViewName("index");
            registry.addViewController("/login.html").setViewName("login");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    05. 验证码配置类
    @Configuration
    public class KaptchaConfig {
    
        @Bean
        public Producer kaptcha() {
            Properties properties = new Properties();
            //1.验证码宽度
            properties.setProperty("kaptcha.image.width", "150");
            //2.验证码高度
            properties.setProperty("kaptcha.image.height", "50");
            //3.验证码字符串
            properties.setProperty("kaptcha.textproducer.char.string", "0123456789");
            //4.验证码长度
            properties.setProperty("kaptcha.textproducer.char.length", "4");
            Config config = new Config(properties);
            DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
            defaultKaptcha.setConfig(config);
            return defaultKaptcha;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    06. 生成验证码
    @Controller
    public class VerifyCodeController {
        private final Producer producer;
    
        @Autowired
        public VerifyCodeController(Producer producer) {
            this.producer = producer;
        }
    
        @RequestMapping("/vc.jpg")
        public void verifyCode(HttpServletResponse response, HttpSession session) throws IOException {
            //1.生成验证码
            String verifyCode = producer.createText();
            //2.保存到中 session
            session.setAttribute("kaptcha", verifyCode);
            //3.生成图片
            BufferedImage bi = producer.createImage(verifyCode);
            //4.响应图片
            response.setContentType("image/png");
            ServletOutputStream os = response.getOutputStream();
            ImageIO.write(bi, "jpg", os);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    07. 配置 SpringSecurity
    @Configuration
    public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
    
        @Bean
        public UserDetailsService userDetailsService(){
            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(userDetailsService());
        }
    
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            // 开启请求的权限管理
            http.authorizeRequests()
                	// 访问登录页面放行
                    .mvcMatchers("/login.html").permitAll()
                	// 访问验证码放行
                    .mvcMatchers("/vc.jpg").permitAll()
                    .anyRequest().authenticated()
                    .and()
                    .formLogin()
                    .loginPage("/login.html")
                    .loginProcessingUrl("/doLogin")
                    .usernameParameter("uname")
                    .passwordParameter("passwd")
                    .defaultSuccessUrl("/index.html",true)
                    .failureUrl("/login.html")
                    .and()
                    .csrf().disable();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    访问项目,跳转到登录页面:
    在这里插入图片描述

    08. 自定义过滤器KaptchaFilter 实现验证码的验证

    在UsernamePasswordAuthenticationFilter过滤器并没有实现验证码的认证:

    public class UsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
        
        @Override
        public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
            throws AuthenticationException {
            if (this.postOnly && !request.getMethod().equals("POST")) {
                throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
            }
            String username = obtainUsername(request);
            username = (username != null) ? username : "";
            username = username.trim();
            String password = obtainPassword(request);
            password = (password != null) ? password : "";
            UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
            // Allow subclasses to set the "details" property
            setDetails(request, authRequest);
            return this.getAuthenticationManager().authenticate(authRequest);
        }
        
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    因此如果想要在登录请求时验证验证码,需要自定义过滤器KaptchaFilter实现验证码验证逻辑实现验证码的验证,放在UsernamePasswordAuthenticationFilter的位置:

    public class KaptchaFilter extends UsernamePasswordAuthenticationFilter {
    
        private static final String FORM_KAPTCHA_KEY = "kaptcha";
        private String kaptchaParameter = FORM_KAPTCHA_KEY;
    
        public void setKaptchaParameter(String kaptchaParameter){
            this.kaptchaParameter = kaptchaParameter;
        }
    
        public String getKaptchaParameter(){
            return kaptchaParameter;
        }
    
        @Override
        public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
            if (!request.getMethod().equals("POST")) {
                throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
            }
            // 1. 从请求中获取验证码
            String verifyCode = request.getParameter(getKaptchaParameter());
            // 2. 从session中获取验证码
            String sessionVerifyCode = (String)request.getSession().getAttribute("kaptcha");
            // 3. 比较
            if(!ObjectUtils.isEmpty(verifyCode) && !ObjectUtils.isEmpty(sessionVerifyCode)
                                                && verifyCode.equalsIgnoreCase(sessionVerifyCode)){
                return super.attemptAuthentication(request,response);
            }
            throw new KaptchaNotMatchException("验证码认证异常");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    //自定义验证码认证异常
    public class KaptchaNotMatchException extends AuthenticationException {
        public KaptchaNotMatchException(String msg, Throwable cause) {
            super(msg, cause);
        }
    
        public KaptchaNotMatchException(String msg) {
            super(msg);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    09. 配置 SpringSecurity

    修改SpringSecurity配置,将KaptchaFilter放在UsernamePasswordAuthenticationFilter位置:

    @Configuration
    public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
    
        @Bean
        public UserDetailsService userDetailsService(){
            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(userDetailsService());
        }
    
        // 暴露自定义的authenticationManager
        @Bean
        public AuthenticationManager authenticationManager() throws Exception {
            return super.authenticationManager();
        }
    
        @Bean
        public KaptchaFilter kaptchaFilter() throws Exception {
            KaptchaFilter kaptchaFilter = new KaptchaFilter();
            kaptchaFilter.setFilterProcessesUrl("/doLogin");
            kaptchaFilter.setUsernameParameter("uname");
            kaptchaFilter.setKaptchaParameter("passwd");
            kaptchaFilter.setKaptchaParameter("kaptcha");
            // 认证管理器
            kaptchaFilter.setAuthenticationManager(authenticationManagerBean());
            // 指定认证成功后的处理
            kaptchaFilter.setAuthenticationSuccessHandler(((request, response, authentication) -> {
                response.sendRedirect("/index.html");
            }));
            // 指定认证失败后的处理
            kaptchaFilter.setAuthenticationFailureHandler(((request, response, exception) -> {
                response.sendRedirect("/login.html");
            }));
            return kaptchaFilter;
        }
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            // 开启请求的权限管理
            http.authorizeRequests()
                    .mvcMatchers("/login.html").permitAll()
                    .mvcMatchers("/vc.jpg").permitAll()
                    .anyRequest().authenticated()
                    .and()
                    .formLogin()
                    .loginPage("/login.html")
                    .loginProcessingUrl("/doLogin")
                    .usernameParameter("uname")
                    .passwordParameter("passwd")
                    .defaultSuccessUrl("/index.html",true)
                    .failureUrl("/login.html")
                    .and()
                    .csrf().disable();
            http.addFilterAt(kaptchaFilter(), UsernamePasswordAuthenticationFilter.class);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    10. 源码分析

    ① 直接访问:localhost:8080/doLogin

    在这里插入图片描述

    ② 请求首先进入认证处理入口 AbstractAuthenticationProcessingFilter 过滤器判断是否需要认证并尝试认证:

    public abstract class AbstractAuthenticationProcessingFilter extends GenericFilterBean
        implements ApplicationEventPublisherAware, MessageSourceAware {
        
        private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws IOException, ServletException {
            // 判断是否需要是配置的请求:kaptchaFilter.setFilterProcessesUrl("/doLogin");
            if (!requiresAuthentication(request, response)) {
                chain.doFilter(request, response);
                return;
            }
            try {
                // 调用子类的方法尝试认证
                Authentication authenticationResult = attemptAuthentication(request, response);
                if (authenticationResult == null) {
                    return;
                }
                this.sessionStrategy.onAuthentication(authenticationResult, request, response);
                // Authentication success
                if (this.continueChainBeforeSuccessfulAuthentication) {
                    chain.doFilter(request, response);
                }
                successfulAuthentication(request, response, chain, authenticationResult);
            }
            catch (InternalAuthenticationServiceException failed) {
                // Authentication failed
                unsuccessfulAuthentication(request, response, failed);
            }
            catch (AuthenticationException ex) {
                // Authentication failed
                unsuccessfulAuthentication(request, response, ex);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    ② 然后进入自定义过滤器 KaptchaFilter 进行验证码的认证:

    public class KaptchaFilter extends UsernamePasswordAuthenticationFilter {
    
        private static final String FORM_KAPTCHA_KEY = "kaptcha";
        private String kaptchaParameter = FORM_KAPTCHA_KEY;
    
        public void setKaptchaParameter(String kaptchaParameter){
            this.kaptchaParameter = kaptchaParameter;
        }
    
        public String getKaptchaParameter(){
            return kaptchaParameter;
        }
    
        @Override
        public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
            if (!request.getMethod().equals("POST")) {
                throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
            }
            // 1. 从请求中获取验证码
            String verifyCode = request.getParameter(getKaptchaParameter());
            // 2. 从session中获取验证码
            String sessionVerifyCode = (String)request.getSession().getAttribute("kaptcha");
            // 3. 比较
            if(!ObjectUtils.isEmpty(verifyCode) && !ObjectUtils.isEmpty(sessionVerifyCode)
                                                && verifyCode.equalsIgnoreCase(sessionVerifyCode)){
                return super.attemptAuthentication(request,response);
            }
            throw new KaptchaNotMatchException("验证码认证异常");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    ③ 验证码验证通过后,进入 UsernamePasswordAuthenticationFilter 过滤器进行用户名和密码的认证:

    public class UsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
        
        @Override
        public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
            throws AuthenticationException {
            if (this.postOnly && !request.getMethod().equals("POST")) {
                throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
            }
            String username = obtainUsername(request);
            username = (username != null) ? username : "";
            username = username.trim();
            String password = obtainPassword(request);
            password = (password != null) ? password : "";
            UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
            // Allow subclasses to set the "details" property
            setDetails(request, authRequest);
            return this.getAuthenticationManager().authenticate(authRequest);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    2. 前后端分离开发添加验证码的认证

    在这里插入图片描述

    01. 项目依赖
    
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-securityartifactId>
    dependency>
    
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-webartifactId>
    dependency>
    
    <dependency>
        <groupId>org.projectlombokgroupId>
        <artifactId>lombokartifactId>
        <optional>trueoptional>
    dependency>
    
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-testartifactId>
        <scope>testscope>
    dependency>
    
    
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-thymeleafartifactId>
    dependency>
    
    
    <dependency>
        <groupId>com.github.pengglegroupId>
        <artifactId>kaptchaartifactId>
        <version>2.3.2version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    02. 验证码配置类
    @Configuration
    public class KaptchaConfig {
    
        @Bean
        public Producer kaptcha() {
            Properties properties = new Properties();
            //1.验证码宽度
            properties.setProperty("kaptcha.image.width", "150");
            //2.验证码高度
            properties.setProperty("kaptcha.image.height", "50");
            //3.验证码字符串
            properties.setProperty("kaptcha.textproducer.char.string", "0123456789");
            //4.验证码长度
            properties.setProperty("kaptcha.textproducer.char.length", "4");
            Config config = new Config(properties);
            DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
            defaultKaptcha.setConfig(config);
            return defaultKaptcha;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    03. 生成验证码
    @RestController
    public class VerifyCodeController {
    
        private final Producer producer;
    
        @Autowired
        public VerifyCodeController(Producer producer) {
            this.producer = producer;
        }
    
        @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());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    04. 配置 SpringSecurity
    @Configuration
    public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
    
        @Bean
        public UserDetailsService userDetailsService(){
            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(userDetailsService());
        }
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            // 开启请求的权限管理
            http.authorizeRequests()
                    .anyRequest().authenticated()
                    .and()
                    .formLogin()
                    .and()
                	// 认证失败异常处理
                    .exceptionHandling()
                    .authenticationEntryPoint(new MyAuthenticationEntryPoint())
                    .and()
                    .csrf().disable();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint {
        @Override
        public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
            response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            response.getWriter().println("请认证之后再去处理");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    05. 自定义过滤器 LoginKaptchaFilter 实现验证码的验证

    在UsernamePasswordAuthenticationFilter过滤器并没有实现验证码的认证:

    public class LoginKaptchaFilter extends UsernamePasswordAuthenticationFilter {
    
        public static final String FORM_KAPTCHA_KEY = "kaptcha";
    
        private String kaptchaParameter = FORM_KAPTCHA_KEY;
    
        public String getKaptchaParameter() {
            return kaptchaParameter;
        }
    
        public void setKaptchaParameter(String kaptchaParameter) {
            this.kaptchaParameter = kaptchaParameter;
        }
    
        @Override
        public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
            if (!request.getMethod().equals("POST")) {
                throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
            }
    
            if(request.getContentType().equalsIgnoreCase(MediaType.APPLICATION_JSON_VALUE)){
                try {
                    // 1.获取请求jsonString数据,并转为Map对象
                    Map<String,String> userInfo = new ObjectMapper().readValue(request.getInputStream(), Map.class);
                    // 获取请求中验证码
                    String kaptcha = userInfo.get(getKaptchaParameter());
                    // 获取请求中用户名
                    String username = userInfo.get(getUsernameParameter());
                    // 获取请求中密码
                    String password = userInfo.get(getPasswordParameter());
    
                    // 2.获取session中验证码
                    String sessionKaptcha = (String)request.getSession().getAttribute("kaptcha");
                    if(!ObjectUtils.isEmpty(sessionKaptcha) && !ObjectUtils.isEmpty(kaptcha)
                            && kaptcha.equalsIgnoreCase(sessionKaptcha)){
                        // 3. 获取用户名和密码认证
                        UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username,password);
                        setDetails(request,authRequest);
                        return this.getAuthenticationManager().authenticate(authRequest);
                    }
                    throw new KaptchaNotMatchException("验证码不正确");
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            // 如果请求不是json数据,调用父类的方法尝试认证
            return super.attemptAuthentication(request,response);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    06. 配置 SpringSecurity
    @Configuration
    public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
    
        @Bean
        public UserDetailsService userDetailsService(){
            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(userDetailsService());
        }
    
        // 暴露自定义的authenticationManager
        @Bean
        public AuthenticationManager authenticationManager() throws Exception {
            return super.authenticationManager();
        }
    
      public LoginKaptchaFilter loginKaptchaFilter() throws Exception {
            LoginKaptchaFilter loginKaptchaFilter = new LoginKaptchaFilter();
            loginKaptchaFilter.setFilterProcessesUrl("/doLogin");
            loginKaptchaFilter.setKaptchaParameter("kaptcha");
            loginKaptchaFilter.setUsernameParameter("uname");
            loginKaptchaFilter.setPasswordParameter("passwd");
            loginKaptchaFilter.setAuthenticationManager(authenticationManagerBean());
            loginKaptchaFilter.setAuthenticationSuccessHandler(new MyAuthenticationSuccessHandler());
            loginKaptchaFilter.setAuthenticationFailureHandler(new MyAuthenticationFailureHandler());
            return loginKaptchaFilter;
      }
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            // 开启请求的权限管理
            http.authorizeRequests()
                    .anyRequest().authenticated()
                    .and()
                    .formLogin()
                    .and()
                    .exceptionHandling()
                    .authenticationEntryPoint(new MyAuthenticationEntryPoint())
                    .and()
                    .csrf().disable();
            http.addFilterAt(loginKaptchaFilter(), UsernamePasswordAuthenticationFilter.class);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    测试:

    在这里插入图片描述

  • 相关阅读:
    基于 HPSO 与多核 LSSVM 的网络入侵检测
    无人直播间带货还能做吗?
    Prototype 原型模式简介与 C# 示例【创建型4】【设计模式来了_4】
    [Gradle]IDEA GradleUse Gradle from选项
    NeuroImage | 右侧颞上回在语义规则学习中的作用:来自强化学习模型的证据
    稳压二极管的原理,它有什么作用?
    thinkphp5.0 composer 安装oss提示php版本异常
    $\Beta$分布推导与可视化
    20220810
    我的面试(1年经验)
  • 原文地址:https://blog.csdn.net/qq_42764468/article/details/126900499