栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

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

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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

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

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

认证流程

Filter实现图形化验证码

我们在

SpringSecurity认证流程源码解析中介绍了SpringSecurity的认证流程

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

    public interface Authentication extends Principal, Serializable {
        
        Collection getAuthorities();
        
        Object getCredentials();
        
        Object getDetails();
        
        Object getPrincipal();
        
        boolean isAuthenticated();
        void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException;
    }

说明:

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

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

ProviderManager管理多个AuthenticationProvider

UsernamePasswordAuthenticationFilter

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

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

public abstract class AbstractAuthenticationProcessingFilter extends GenericFilterBean
      implements ApplicationEventPublisherAware, MessageSourceAware {

   protected ApplicationEventPublisher eventPublisher;

   protected AuthenticationDetailsSource authenticationDetailsSource = new WebAuthenticationDetailsSource();
     ...
   }

WebAuthenticationDetailsSource

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

自定义WebAuthenticationDetails

有了HttpServletRequest之后,一切都将变得非常顺畅。基于图形验证码的场景,我们可以继承 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 {
    @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 imageCodeWebAuthenticationDetailsSource;

    @Autowired
    @Qualifier("imageCodeAuthenticationProvider")
    private AuthenticationProvider imageCodeAuthenticationProvider;
    
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //super.configure(auth);
        auth.authenticationProvider(imageCodeAuthenticationProvider);
    }
    
    @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,输入错误的验证码,结果为

如果您觉得本文不错,欢迎关注,点赞,收藏支持,您的关注是我坚持的动力!
原创不易,转载请注明出处,感谢支持!如果本文对您有用,欢迎转发分享!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/782147.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号