​SpringSecurity-7-自定义AuthenticationProvider实现图形验证码

简介: 上一章节我们介绍了如何使用过滤器(Filter)实现图形验证,这是属于Servlet层面,比较简单容易理解。那么这次我们介绍SpringSecurity提供的另一种比较高端的实现图形化验证码,这就是AuthenticationProvider自定义认证。

SpringSecurity-7-自定义AuthenticationProvider实现图形验证码


上一章节我们介绍了如何使用过滤器(Filter)实现图形验证,这是属于Servlet层面,比较简单容易理解。那么这次我们介绍SpringSecurity提供的另一种比较高端的实现图形化验证码,这就是AuthenticationProvider自定义认证。



认证流程

我们在



51faa237ac09d52a9668bb50670b9f60.png


其中介绍了系统的用户信息,保存在SpringSecurity的主体(Principal)中。主体中包含了所有经过验证用户的权限,详细信息等内容。在SpringSecurity中将其封装放在Authentication中,代码如下

    public interface Authentication extends Principal, Serializable {
        /**
         * 获取用户权限
         * @return
         */
        Collection<? extends GrantedAuthority> getAuthorities();
        /**
         * 获取用于的凭证,用户密码
         * @return
         */
        Object getCredentials();
        /**
         * 用户的详细信息
         * @return
         */
        Object getDetails();
        /**
         * 用户凭证,一般为用户名
         * @return
         */
        Object getPrincipal();
        /**
         * 用户验证是否成功
         * @return
         */
        boolean isAuthenticated();
        void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException;
    }


说明:


Authentication中包含主体权限列表,主体凭据,主体的详细信息,及是否验证成功等。


AuthenticationProvider被SpringSecurity定义为一个验证过程


ProviderManager管理多个AuthenticationProvider


UsernamePasswordAuthenticationFilter

我们查看UsernamePasswordAuthenticationFilter类发现设置用户信息的方法setDetails方法36882ede69c89437aa1ff839630ce624.png


从源码我们可以看出authenticationDetailsSource是由AbstractAuthenticationProcessingFilter提供的AbstractAuthenticationProcessingFilter部分源码如下

public abstract class AbstractAuthenticationProcessingFilter extends GenericFilterBean
      implements ApplicationEventPublisherAware, MessageSourceAware {
   protected ApplicationEventPublisher eventPublisher;
   protected AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = new WebAuthenticationDetailsSource();
     ...
   }


WebAuthenticationDetailsSource



在UsernamePasswordAuthenticationFilter中使用的AuthenticationDetailsSource是一个标准的Web认证 源,携带的是用户的sessionId和IP地址。源码如图所示


e9c5467dd738d4c5d034eeb172eec526.png


自定义WebAuthenticationDetails有了HttpServletRequest之后,一切都将变得非常顺畅。基于图形验证码的场景,我们可以继承 WebAuthenticationDetails,并扩展需要的信息。因此我们可以自定义WebAuthenticationDetails存储额外信息。

/**
 *自定义WebAuthenticationDetails存储额外的图形验证信息
 */
public class ImageCodeWebAuthenticationDetails extends WebAuthenticationDetails {
    /**
     * 图形信息是否验证成功
     */
    private boolean imageCodeIsRight;
    public boolean getImageCodeIsRight(){
        return imageCodeIsRight;
    }
    public ImageCodeWebAuthenticationDetails(HttpServletRequest request) {
        super(request);
        // 先获取seesion中的验证码
        HttpSession session = request.getSession();
        String sessionCode = (String) session.getAttribute(CaptchaController.SESSION_KEY);
        // 获取用户输入的验证码
        String inpuCode = request.getParameter("code");
        if(!StringUtils.isEmpty(inpuCode)){
            //清除验证码,不论验证成功还是失败,都需要清除验证码,并且在验证失败的时候需要刷新验证码
            session.removeAttribute("code");
            if(!StringUtils.isEmpty(sessionCode)&& inpuCode.equalsIgnoreCase(sessionCode) ){
                this.imageCodeIsRight=true;
            }
        }
    }
}


自定义的AuthenticationDetailsSource。

@Component("imageCodeWebAuthenticationDetailsSource")
public class ImageCodeWebAuthenticationDetailsSource implements AuthenticationDetailsSource<HttpServletRequest, WebAuthenticationDetails> {
    @Override
    public ImageCodeWebAuthenticationDetails buildDetails(HttpServletRequest context) {
        return new ImageCodeWebAuthenticationDetails(context);
    }
}


自定义AuthenticationProvider。

@Component("imageCodeAuthenticationProvider")
public class ImageCodeAuthenticationProvider extends DaoAuthenticationProvider {
    public ImageCodeAuthenticationProvider(UserDetailsService userDetailsService, PasswordEncoder passwordEncoder) {
        this.setUserDetailsService(userDetailsService);
        this.setPasswordEncoder(passwordEncoder);
    }
    @Override
    protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
        //获取详细信息
        ImageCodeWebAuthenticationDetails  details = (ImageCodeWebAuthenticationDetails)authentication.getDetails();
        //如果验证码不正确,抛出异常
        if(!details.getImageCodeIsRight()){
            throw new ValidateCodeException("验证码输入错误");
        }
        super.additionalAuthenticationChecks(userDetails, authentication);
    }
}


修改配置类

想要应用自定义的 AuthenticationProvider 和 AuthenticationDetailsSource,还需在LearnSrpingSecurity中完成剩余的配置。

/**
 * 安全配置类
 */
@EnableWebSecurity
public class LearnSrpingSecurity extends WebSecurityConfigurerAdapter {
    @Autowired
    @Qualifier("imageCodeWebAuthenticationDetailsSource")
    private AuthenticationDetailsSource<HttpServletRequest,WebAuthenticationDetails> imageCodeWebAuthenticationDetailsSource;
    @Autowired
    @Qualifier("imageCodeAuthenticationProvider")
    private AuthenticationProvider imageCodeAuthenticationProvider;
    /**
     * 认证管理器
     * 1.认证信息提供方式(用户名、密码、当前用户的资源权限)
     * 2.可采用内存存储方式,也可能采用数据库方式等
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //super.configure(auth);
        auth.authenticationProvider(imageCodeAuthenticationProvider);
    }
    /**
     * 资源权限配置(过滤器链):
     * 1、被拦截的资源
     * 2、资源所对应的角色权限
     * 3、定义认证方式:httpBasic 、httpForm
     * 4、定制登录页面、登录请求地址、错误处理方式
     * 5、自定义 spring security 过滤器
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable() //禁用跨站csrf攻击防御,后面的章节会专门讲解
                .formLogin()
                .authenticationDetailsSource(imageCodeWebAuthenticationDetailsSource)
                .loginPage("/login/page")//一旦用户的请求没有权限就跳转到这个页面
                .loginProcessingUrl("/login/form")//登录表单form中action的地址,也就是处理认证请求的路径
                .usernameParameter("username")///登录表单form中用户名输入框input的name名,不修改的话默认是username
                .passwordParameter("password")//form中密码输入框input的name名,不修改的话默认是password
                //.defaultSuccessUrl("/syslog")//登录认证成功后默认转跳的路径
                //.failureHandler(failureHandler)
                .and()
                .authorizeRequests()
                .antMatchers("/login/page","/code/image").permitAll()//不需要通过登录验证就可以被访问的资源路径
                .anyRequest().authenticated();
    }
}



主要修改如图

测试


我们使用浏览器浏览http://localhost:8888,输入错误的验证码,结果为

如果您觉得本文不错,欢迎关注,点赞,收藏支持,您的关注是我坚持的动力!

目录
相关文章
|
2月前
|
存储 前端开发 Java
验证码案例 —— Kaptcha 插件介绍 后端生成验证码,前端展示并进行session验证(带完整前后端源码)
本文介绍了使用Kaptcha插件在SpringBoot项目中实现验证码的生成和验证,包括后端生成验证码、前端展示以及通过session进行验证码校验的完整前后端代码和配置过程。
242 0
验证码案例 —— Kaptcha 插件介绍 后端生成验证码,前端展示并进行session验证(带完整前后端源码)
|
7月前
|
Java
JavaSE自定义验证码图片生成器
设计项目的时候打算在原有的功能上补充验证码功能,在实现了邮箱验证码之后想着顺便把一个简单的图片验证码生成器也实现一下,用作分享。
43 1
|
7月前
|
JSON 缓存 前端开发
验证码demo(简单实现)
验证码demo(简单实现)
112 0
|
7月前
|
前端开发 JavaScript Java
springboot 集成easy-captcha实现图像验证码显示和登录
springboot 集成easy-captcha实现图像验证码显示和登录
421 0
|
7月前
|
NoSQL 前端开发 Java
spring boot3登录开发-2(1图形验证码接口实现)
spring boot3登录开发-2(1图形验证码接口实现)
245 2
|
安全 Java 数据库连接
四.SpringSecurity基础-自定义登录流程
SpringSecurity基础-自定义登录流程
|
人工智能 安全 前端开发
Spring Security系列教程13--基于过滤器实现图形验证码
前言 在前两个章节中,一一哥 带大家学习了Spring Security内部关于认证授权的核心API,以及认证授权的执行流程和底层原理。掌握了这些之后,对于Spring Security,我们不仅做到了 "知其然",而且也做到了 "知其所以然"! 在现在的求职环境下,只知道某个技能点的用法是远远不够的,面试官会要求我们研究某个技术的底层实现原理,所以虽然前面的两章内容掌握起来很有难度,但是还是希望各位小伙伴结合源码认真研读,这样你才能在编程之路上走的更远更高! 总是研究底层,对于我们初学者来说,既有难度,也会影响咱们的学习积极性,所以从本篇文章开始,咱们继续学习Spring Securit
397 0
|
Java
SpringSecurity-6-基于Filter实现图形验证码
SpringSecurity中有多种方式实现图像验证码,使用自定义过滤器去处理验证码逻辑是最简单的方式,只要将过滤器添加到合适的位置,当登录的时候,对验证码进行校验,成功就放行,失败则抛出异常。
171 0
|
JSON 安全 搜索推荐
​SpringSecurity-5-自定义登录验证
​SpringSecurity-5-自定义登录验证
167 0