Spring Security自定义身份验证 - AuthenticationProvider与UserDetailsS​​ervice

Evg*_*rov 34 java spring spring-mvc spring-security

据我所知,当你想在Spring Security中进行自定义身份验证时,你可以实现自定义AuthenticationProvider或自定义UserDetailsService.

@Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth    
            //.authenticationProvider(authProvider)  // option 1
            .userDetailsService(userDetailsService); // option 2

    }
Run Code Online (Sandbox Code Playgroud)

在AuthenticationProvider中,您可以检查用户名和密码,并返回Authentication其中的自定义对象.

public Authentication authenticate(Authentication authentication){
        if (checkUsernameAndPassword(authentication)) {
            CustomUserDetails userDetails = new CustomUserDetails();
            //add whatever you want to the custom user details object
            return new UsernamePasswordAuthenticationToken(userDetails, password, grantedAuths);
        } else {
            throw new BadCredentialsException("Unable to auth against third party systems");
        }
    }
Run Code Online (Sandbox Code Playgroud)

UserDetailsService您只获取用户名时,当您返回自定义UserDeatails时,框架会检查密码.

public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        CustomUserDetails user = new CustomUserDetails();
        //add whatever you want to the custom user details object
        return user;
    }
Run Code Online (Sandbox Code Playgroud)

看起来两者都可以产生类似的结果.所以问题是有什么区别?何时使用一对另一对?

小智 37

答案在你的问题里面.当您使用其他身份验证系统,并且您自己的数据库/数据模型中未提供密码时,您必须使用AuthenticationProvider.例如,我参与了一个客户拥有集中认证系统(CAS)的项目,所以我的系统不知道密码,我必须实现AuthenticationProvider并将给定的密码发送给CAS,并按照它的答案.

但是在另一个系统中,我将密码存储在我的数据库中,所以我所要做的就是实现UserDetailsS​​ervice并检查用户是否存在于我的数据库中,spring-security必须完成剩下的工作.


Gau*_*ula 12

从Spring安全文档开始, https://docs.spring.io/spring-security/site/docs/5.0.0.RC1/reference/htmlsingle/#overall-architecture

关于UserDetailsS​​ervice经常会有一些混乱.它纯粹是用户数据的DAO,除了将数据提供给框架内的其他组件之外,不执行任何其他功能.特别是,它不会对用户进行身份验证,这是由AuthenticationManager完成的.在许多情况下,如果您需要自定义身份验证过程,则直接实现AuthenticationProvider会更有意义.

AuthenticationProvider和UserDetailsS​​ervice具有不同的用途.

AuthenticationProvider验证(比较)用户(请求)提供的用户名和密码与系统用户(这可以是任何系统,如DB维护注册用户列表)

UserDetailsS​​ervice实现的责任是获取与用户提供的用户名匹配的系统用户详细信息.这里只是获取具有相同用户名的用户,并且不告诉应用程序认证是成功还是失败.

示例:Spring提供以下作为默认设置,以根据数据库验证用户详细信息

  • AuthenticationProvider - DaoAuthenticationProvider扩展AbstractUserDetailsAuthenticationProvider,通过传递用户名,Authentication对象来调用authenticate方法
  • UserDetailsS​​ervice - JdbcDaoImpl
  • 认证流程
  1. DaoAuthenticationProvider的职责是验证从数据库用户请求获得的用户名和密码.
  2. 为了获得相应的数据库用户,它要求UserDetailsS​​ervice Implementataion JdbcDaoImpl从数据库获取一个UserDetail对象,其名称与请求username相同.这里JdbcDaoImpl只从系统中获取UserDetails对象.它将发送回在DB中找到的用户或发送异常找不到该用户.
  3. 如果在DB中找到用户详细信息,则DaoAuthenticationProvider继续检查请求用户密码,DB找到用户密码,否则验证失败.
  4. DaoAuthenticationProvider将根据JdbcDaoImpl响应来响应用户是否经过身份验证.

看看这里更好地理解它:

AuthenticationProvider - DaoAuthenticationProvider 扩展AbstractUserDetailsAuthenticationProvider

UserDetailsS​​ervice - JdbcDaoImpl

UserDetails - 用户


Den*_*ang 5

这两者是相关的,但被 Spring Security 故意分开。如果企业有多个系统,UserDetailsS​​ervice 将提供您的特定系统保存的特定用户的信息,即使身份验证可能完全由另一个系统执行。在一个简单的系统中,它们可以被组合起来。例如,数据库调用将验证用户名/密码并检索所有该用户的电子邮件、ID 等。

根据 Spring Security 参考: http://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#getting-started

关于 UserDetailsS​​ervice 经常存在一些混淆。它纯粹是一个用于用户数据的 DAO,除了将该数据提供给框架内的其他组件之外,不执行任何其他功能。特别是,它不会对用户进行身份验证,这是由 AuthenticationManager 完成的。在许多情况下,如果您需要自定义身份验证过程,那么直接实现 AuthenticationProvider 更有意义。