我什么时候应该在 Spring Boot 应用程序中覆盖 Spring Security 的 configure(AuthenticationManagerBuilder auth)?

elv*_*vis 6 java authentication spring spring-security spring-boot

我正在 Spring Boot 应用程序中学习 Spring Security,我有一个非常简单的例子。我看到,如果我发表评论,configure(AuthenticationManagerBuilder auth)则没有区别。无论我是否使用它,我都有相同的输出,我需要使用硬编码凭据登录。

@Configuration
@RequiredArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter {

//    private final MyUserDetailsService myUserDetailsService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
                http
                .csrf().disable()
                        .authorizeRequests().anyRequest().authenticated()
                .and()
                        .httpBasic();
    }

//    @Override
//    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//        auth.userDetailsService(myUserDetailsService);
//    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}
Run Code Online (Sandbox Code Playgroud)

MyUserDetailsS​​ervice 类:

@Service
public class MyUserDetailsService implements UserDetailsService {

    private static final String USERNAME = "john";
    private static final String PASSWORD = "$2a$10$fDDUFA8rHAraWnHAERMAv.4ReqKIi7mz8wrl7.Fpjcl1uEb6sIHGu";

    @Override
    public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {

        if (!userName.equals(USERNAME)) {
            throw new UsernameNotFoundException(userName);
        }

        return new User(USERNAME, PASSWORD, new ArrayList<>());
    }
}
Run Code Online (Sandbox Code Playgroud)

休息控制器:

@RestController
public class HelloController {

    @GetMapping("/hello")
    public String hello() {
        return "Hello World!";
    }
}
Run Code Online (Sandbox Code Playgroud)

我想知道实现UserDetailsService接口是否等同于覆盖configure(AuthenticationManagerBuilder auth). 谢谢!

Pat*_*mil 9

用户详情服务

\n
\n

DaoAuthenticationProvider使用 UserDetailsS​​ervice 来检索\n用户名、密码和其他用于使用用户名和密码进行身份验证的属性。Spring Security 提供UserDetailsS​​ervice 的内存中JDBC实现。

\n

您可以通过将自定义\nUserDetailsS​​ervice 公开为 bean 来定义自定义身份验证。例如,以下内容将\n自定义身份验证,假设 CustomUserDetailsS​​ervice\n实现 UserDetailsS​​ervice

\n
\n

UserDetailsS ​​ervice接口用于检索与用户相关的数据。它有一个名为的方法loadUserByUsername(),可以重写该方法来自定义查找用户的过程。为了提供我们自己的用户服务,我们需要实现UserDetailsS​​ervice接口。

\n

loadUserByUsername(String username)返回UserDetails,其中org.springframework.security.core.userdetails包含getUsername(), getPassword(), getAuthorities()进一步用于 spring security 的方法。

\n

我们还可以通过实现UserDetailsorg.springframework.security.core.userdetails.User接口来自定义(这里用作new User(USERNAME, PASSWORD, new ArrayList<>()))。

\n

在这里,我分享一下UserDetailsS​​ervice服务的理想使用方式

\n
@Component("userDetailsService")\npublic class DomainUserDetailsService implements UserDetailsService {\n\n    private final Logger log = LoggerFactory.getLogger(DomainUserDetailsService.class);\n\n    private final UserRepository userRepository;\n\n    public DomainUserDetailsService(UserRepository userRepository) {\n        this.userRepository = userRepository;\n    }\n\n    @Override\n    @Transactional\n    public UserDetails loadUserByUsername(final String login) {\n        log.debug("Authenticating {}", login);\n\n        if (new EmailValidator().isValid(login, null)) {\n            return userRepository.findOneWithAuthoritiesByEmailIgnoreCase(login)\n                .map(user -> createSpringSecurityUser(login, user))\n                .orElseThrow(() -> new UsernameNotFoundException("User with email " + login + " was not found in the database"));\n        }\n\n        String lowercaseLogin = login.toLowerCase(Locale.ENGLISH);\n        return userRepository.findOneWithAuthoritiesByLogin(lowercaseLogin)\n            .map(user -> createSpringSecurityUser(lowercaseLogin, user))\n            .orElseThrow(() -> new UsernameNotFoundException("User " + lowercaseLogin + " was not found in the database"));\n\n    }\n\n    private org.springframework.security.core.userdetails.User createSpringSecurityUser(String lowercaseLogin, User user) {\n        if (!user.getActivated()) {\n            throw new UserNotActivatedException("User " + lowercaseLogin + " was not activated");\n        }\n        List<GrantedAuthority> grantedAuthorities = user.getAuthorities().stream()\n            .map(authority -> new SimpleGrantedAuthority(authority.getName()))\n            .collect(Collectors.toList());\n        return new org.springframework.security.core.userdetails.User(user.getLogin(),\n            user.getPassword(),\n            grantedAuthorities);\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

当调用 loadUserByUsername 时?

\n

如上所述,它通常由 DaoAuthenticationProvide 实例调用以对用户进行身份验证。例如,当提交用户名和密码时,将调用 UserdetailsS​​ervice 来查找该用户的密码以查看其是否正确。它通常还会提供有关用户的一些其他信息,例如权限和您可能希望登录用户访问的任何自定义字段(例如电子邮件)

\n

内存中身份验证

\n

在这里,您使用了用户名和密码的静态值,可以使用内存中身份验证进行理想的配置,如下所示。

\n

Spring Security\xe2\x80\x99sInMemoryUserDetailsManager实现为在内存中检索的基于用户名/密码的UserDetailsService身份验证提供支持。通过实现接口提供管理。当 Spring Security 配置为接受用户名/密码进行身份验证时,将使用基于身份验证。InMemoryUserDetailsManagerUserDetailsUserDetailsManagerUserDetails

\n
@Bean\npublic UserDetailsService users() {\n    UserDetails user = User.builder()\n        .username("user")\n        .password("{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW")\n        .roles("USER")\n        .build();\n    UserDetails admin = User.builder()\n        .username("admin")\n        .password("{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW")\n        .roles("USER", "ADMIN")\n        .build();\n    return new InMemoryUserDetailsManager(user, admin);\n}\n
Run Code Online (Sandbox Code Playgroud)\n

配置(AuthenticationManagerBuilder 身份验证)

\n

该方法使用AuthenticationManagerBuilder内部使用SecurityBuilder来创建AuthenticationManager。允许轻松构建内存身份验证、LDAP 身份验证、基于 JDBC 的身份验证、添加 UserDetailsS​​ervice 和添加\nAuthenticationProvider。

\n

Spring Security 如何添加/配置 AuthenticationManagerBuilder?

\n
\n

UserDetailsS​​ervice 接口相当于覆盖\nconfigure(AuthenticationManagerBuilder auth)

\n
\n

\n


use*_*814 5

不,这不一样。

应用程序中提供的用户详细信息服务作为 bean 注册到全局身份验证管理器 ( details),并且是所有本地身份验证管理器的后备。

根据应用程序设置,可以有多个本地身份验证管理器。每个本地身份验证管理器将使用配置的默认用户详细信息服务configure(AuthenticationManagerBuilder auth)

我什么时候应该在 Spring Boot 应用程序中覆盖 Spring Security 的配置(AuthenticationManagerBuilder auth)?

如果您有不同的授权/身份验证要求,并且您希望插入自己的身份验证提供程序来满足要求或添加任何内置提供程序(如 ldap 和内存提供程序),则应覆盖。您还可以直接使用如下所示的 http 安全 bean 来完成此操作。

所有身份验证提供程序都会被添加Provider Manager并进行尝试,直到找到一个。

默认情况下,如果不提供任何内容(即没有用户详细信息服务或没有覆盖身份验证管理器),您将拥有默认的全局身份验证管理器和自动配置的用户详细信息管理器(即InMemoryUserDetailsManager在自动配置中配置的用户密码实现UserDetailsServiceAutoConfiguration)。

因此,当您提供用户详细信息服务应用程序 bean 时,自动配置会停止,现在您的全局身份验证管理器已使用提供的 bean 进行配置。

更多细节here

Here很好地解释了这一切是如何结合在一起的。

我还想对 Spring Security 身份验证管理器进行更多扩展,这很容易被忽视。

正如我之前提到的,有全局身份验证管理器和本地身份验证管理器。如果需要的话,配置每项时都需要特别小心。

全局身份验证管理器注释的 java 文档对此进行了解释。

EnableGlobalAuthentication 注释表明注释的类可用于配置 AuthenticationManagerBuilder 的全局实例。例如:

@Configuration 
@EnableGlobalAuthentication  
public class MyGlobalAuthenticationConfiguration {

   @Autowired
   public void configureGlobal(AuthenticationManagerBuilder auth) {
            auth.inMemoryAuthentication().withUser("user").password("password").roles("USER")
                            .and().withUser("admin").password("password").roles("USER", "ADMIN");}} 
Run Code Online (Sandbox Code Playgroud)

使用 EnableGlobalAuthentication 注释的注释还表明带注释的类可用于配置 AuthenticationManagerBuilder 的全局实例。例如:

 @Configuration  
 @EnableWebSecurity  
 public class MyWebSecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) {
            auth.inMemoryAuthentication().withUser("user").password("password").roles("USER")
                            .and().withUser("admin").password("password").roles("USER", "ADMIN");
    }

    // Possibly overridden methods ...  }   
Run Code Online (Sandbox Code Playgroud)

以下注解使用EnableGlobalAuthentication 注解 EnableWebSecurity EnableWebMvcSecurity EnableGlobalMethodSecurity

在没有 EnableGlobalAuthentication 注释的类中配置 AuthenticationManagerBuilder 会产生不可预测的结果。

EnableGlobalAuthentication导入AuthenticationConfiguration负责设置全局身份验证管理器默认配置的配置。

AuthenticationConfiguration配置两个关键部分来创建身份验证管理器 - 用户详细信息和身份验证提供程序。

用户详细信息是使用配置的InitializeUserDetailsBeanManagerConfigurer,身份验证提供程序是使用配置的InitializeAuthenticationProviderBeanManagerConfigurer。两个必需的 bean 都会在应用程序上下文中查找 - 这就是您的用户详细信息服务向全局身份验证管理器注册的方式。

GlobalMethodSecurityConfiguration并且WebSecurityConfigurerAdapter是全局身份验证管理器的消费者。

WebSecurityConfigurerAdapter可用于创建和配置本地身份验证管理器(添加新的身份验证提供程序),并且通常还用于在应用程序中具有不同的身份验证/授权要求,例如 mvc 与 Rest 以及公共端点与管理端点。

仅使用 Spring Security 即可@EnableWebSecurity触发上述流程,作为 Spring Security 过滤器链设置的一部分。对于 Spring Boot,Spring Security 自动配置会触发相同的流程。

在 spring security 5.4 版本中,您可以将 http security 定义为 beans,而无需扩展 WebSecurityConfigurerAdapter 类。Spring Boot 将在 2.4.0 版本中支持此功能。更多细节here

    @Bean
    SecurityFilterChain configure(HttpSecurity http) throws Exception 
      {
         http
            .authenticationProvider(custom authentication provider)
            .userDetailsService( custom user details service)
            .csrf().disable()
                    .authorizeRequests().anyRequest().authenticated()
            .and()
                    .httpBasic();
        return http.build();
      }
Run Code Online (Sandbox Code Playgroud)


kou*_*mln 0

您正在使用在组件扫描时@Service创建 bean 的注释。UserDetailsService无需在 中再次指定AuthenticationManagerBuilder

如果您不使用 @Service 注释,那么您可以通过WebSecurityConfigurerAdapter覆盖AuthenticationManagerBuilder.