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)
MyUserDetailsService 类:
@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)
. 谢谢!
\n\nDaoAuthenticationProvider使用 UserDetailsService 来检索\n用户名、密码和其他用于使用用户名和密码进行身份验证的属性。Spring Security 提供UserDetailsService 的内存中和JDBC实现。
\n您可以通过将自定义\nUserDetailsService 公开为 bean 来定义自定义身份验证。例如,以下内容将\n自定义身份验证,假设 CustomUserDetailsService\n实现 UserDetailsService
\n
UserDetailsS ervice接口用于检索与用户相关的数据。它有一个名为的方法loadUserByUsername()
,可以重写该方法来自定义查找用户的过程。为了提供我们自己的用户服务,我们需要实现UserDetailsService接口。
loadUserByUsername(String username)
返回UserDetails,其中org.springframework.security.core.userdetails
包含getUsername(), getPassword(), getAuthorities()
进一步用于 spring security 的方法。
我们还可以通过实现UserDetailsorg.springframework.security.core.userdetails.User
接口来自定义(这里用作new User(USERNAME, PASSWORD, new ArrayList<>())
)。
在这里,我分享一下UserDetailsService服务的理想使用方式
\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如上所述,它通常由 DaoAuthenticationProvide 实例调用以对用户进行身份验证。例如,当提交用户名和密码时,将调用 UserdetailsService 来查找该用户的密码以查看其是否正确。它通常还会提供有关用户的一些其他信息,例如权限和您可能希望登录用户访问的任何自定义字段(例如电子邮件)
\n在这里,您使用了用户名和密码的静态值,可以使用内存中身份验证进行理想的配置,如下所示。
\nSpring Security\xe2\x80\x99sInMemoryUserDetailsManager
实现为在内存中检索的基于用户名/密码的UserDetailsService
身份验证提供支持。通过实现接口提供管理。当 Spring Security 配置为接受用户名/密码进行身份验证时,将使用基于身份验证。InMemoryUserDetailsManager
UserDetails
UserDetailsManager
UserDetails
@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
内部使用SecurityBuilder来创建AuthenticationManager。允许轻松构建内存身份验证、LDAP 身份验证、基于 JDBC 的身份验证、添加 UserDetailsService 和添加\nAuthenticationProvider。
Spring Security 如何添加/配置 AuthenticationManagerBuilder?
\n\n\nUserDetailsService 接口相当于覆盖\nconfigure(AuthenticationManagerBuilder auth)
\n
不
\n不,这不一样。
应用程序中提供的用户详细信息服务作为 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 的全局实例。例如:
Run Code Online (Sandbox Code Playgroud)@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");}}
使用 EnableGlobalAuthentication 注释的注释还表明带注释的类可用于配置 AuthenticationManagerBuilder 的全局实例。例如:
Run Code Online (Sandbox Code Playgroud)@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 ... }
以下注解使用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)
您正在使用在组件扫描时@Service
创建 bean 的注释。UserDetailsService
无需在 中再次指定AuthenticationManagerBuilder
。
如果您不使用 @Service 注释,那么您可以通过WebSecurityConfigurerAdapter
覆盖AuthenticationManagerBuilder
.
归档时间: |
|
查看次数: |
1051 次 |
最近记录: |