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

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

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

认证流程

我们在

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

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

    public interface Authentication extends PrincipalSerializable {
        /**
         * 获取用户权限
         * @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方法

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

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

public abstract class AbstractAuthenticationProcessingFilter extends GenericFilterBean
      implements ApplicationEventPublisherAwareMessageSourceAware 
{

   protected ApplicationEventPublisher eventPublisher;

   protected AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = new WebAuthenticationDetailsSource();
     ...
   }

WebAuthenticationDetailsSource

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

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

自定义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<HttpServletRequestWebAuthenticationDetails{
    @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();
    }
}

主要修改如图

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

测试

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

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


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

原创不易,转载请注明出处,感谢支持!如果本文对您有用,欢迎转发分享!

原文始发于微信公众号(springboot葵花宝典):​SpringSecurity-7-自定义AuthenticationProvider实现图形验证码

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之家整理,本文链接:https://www.bmabk.com/index.php/post/184248.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之家——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!