我正在学习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();
}
}
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<>());
}
}
RestController:
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "Hello World!";
}
}
我想知道实现UserDetailsService
接口是否等同于覆盖configure(AuthenticationManagerBuilder auth)
。谢谢!
发布于 2020-10-29 00:21:16
UserDetailsService来检索用户名、密码和其他属性,以便使用用户名和密码进行身份验证。Spring Security提供了UserDetailsService的in-memory和JDBC实现。
您可以通过将自定义UserDetailsService公开为bean来定义自定义身份验证。例如,假设CustomUserDetailsService实现了UserDetailsService,以下代码将自定义身份验证
UserDetailsService接口用于检索与用户相关的数据。它有一个名为loadUserByUsername()
的方法,可以重写该方法以定制查找用户的过程。为了提供我们自己的用户服务,我们需要实现UserDetailsService接口。
loadUserByUsername(String username)
返回UserDetails,它是由spring方法组成的org.springframework.security.core.userdetails
的一部分,后者进一步用于spring安全性。
我们还可以通过实现UserDetails接口来自定义org.springframework.security.core.userdetails.User
(这里用作new User(USERNAME, PASSWORD, new ArrayList<>())
)。
在这里,我将分享使用UserDetailsService服务的理想方法
@Component("userDetailsService")
public class DomainUserDetailsService implements UserDetailsService {
private final Logger log = LoggerFactory.getLogger(DomainUserDetailsService.class);
private final UserRepository userRepository;
public DomainUserDetailsService(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
@Transactional
public UserDetails loadUserByUsername(final String login) {
log.debug("Authenticating {}", login);
if (new EmailValidator().isValid(login, null)) {
return userRepository.findOneWithAuthoritiesByEmailIgnoreCase(login)
.map(user -> createSpringSecurityUser(login, user))
.orElseThrow(() -> new UsernameNotFoundException("User with email " + login + " was not found in the database"));
}
String lowercaseLogin = login.toLowerCase(Locale.ENGLISH);
return userRepository.findOneWithAuthoritiesByLogin(lowercaseLogin)
.map(user -> createSpringSecurityUser(lowercaseLogin, user))
.orElseThrow(() -> new UsernameNotFoundException("User " + lowercaseLogin + " was not found in the database"));
}
private org.springframework.security.core.userdetails.User createSpringSecurityUser(String lowercaseLogin, User user) {
if (!user.getActivated()) {
throw new UserNotActivatedException("User " + lowercaseLogin + " was not activated");
}
List<GrantedAuthority> grantedAuthorities = user.getAuthorities().stream()
.map(authority -> new SimpleGrantedAuthority(authority.getName()))
.collect(Collectors.toList());
return new org.springframework.security.core.userdetails.User(user.getLogin(),
user.getPassword(),
grantedAuthorities);
}
}
when loadUserByUsername is invoked?
如上所述,它通常由DaoAuthenticationProvide实例调用以对用户进行身份验证。例如,当提交用户名和密码时,将调用UserdetailsService来查找该用户的密码,以查看该密码是否正确。它通常还会提供有关用户的一些其他信息,例如权限和您可能想要为登录用户访问的任何自定义字段(例如,电子邮件)
在这里,您使用了用户名和密码的静态值,理想情况下可以使用In-Memory Authentication进行配置,如下所示。
Spring Security的InMemoryUserDetailsManager
实现了UserDetailsService
,以支持在内存中检索的基于用户名/密码的身份验证。InMemoryUserDetailsManager
通过实现UserDetailsManager
接口提供对UserDetails
的管理。Spring Security在配置为接受用户名/密码进行身份验证时,会使用基于UserDetails
的身份验证。
@Bean
public UserDetailsService users() {
UserDetails user = User.builder()
.username("user")
.password("{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW")
.roles("USER")
.build();
UserDetails admin = User.builder()
.username("admin")
.password("{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW")
.roles("USER", "ADMIN")
.build();
return new InMemoryUserDetailsManager(user, admin);
}
配置(AuthenticationManagerBuilder身份验证)
此方法使用在内部使用SecurityBuilder创建AuthenticationManager的AuthenticationManagerBuilder
。允许在内存中轻松构建身份验证、LDAP身份验证、基于JDBC的身份验证、添加UserDetailsService和添加AuthenticationProvider。
How Spring Security add/configure AuthenticationManagerBuilder?
UserDetailsService接口等同于覆盖配置(AuthenticationManagerBuilder身份验证)
没有
发布于 2020-10-28 20:10:00
不,这不一样。
应用程序中提供的用户详细信息服务作为bean在全局身份验证管理器(details
)中注册,并且是所有本地身份验证管理器的备用服务。
根据应用程序的设置,可以有多个本地身份验证管理器。每个本地身份验证管理器都将使用使用configure(AuthenticationManagerBuilder auth)
配置的默认用户详细信息服务。
何时应该覆盖Spring Boot应用程序中Spring Security的配置(AuthenticationManagerBuilder身份验证)?
如果您有不同的授权/身份验证要求,您应该覆盖它,您是想插入自己的身份验证提供程序来满足要求,还是想添加任何内置的提供程序,如ldap和内存提供程序。您也可以直接使用http安全bean来完成此操作,如下所示。
所有身份验证提供程序都会添加到Provider Manager
中,并会一直尝试,直到找到一个。
默认情况下,不提供任何内容(例如,不提供用户详细信息服务或不覆盖身份验证管理器),您将拥有默认全局身份验证管理器和自动配置的用户详细信息管理器(即,在UserDetailsServiceAutoConfiguration
自动配置中配置的user password InMemoryUserDetailsManager
实现)。
因此,当您提供user details服务应用程序bean时,自动配置将停止,现在您的全局身份验证管理器已经使用所提供的bean进行了配置。
更多详细信息here
Here
很好地解释了这一切是如何结合在一起的。
我还想对spring安全认证管理器进行更多的扩展,这是很容易被忽略的。
如前所述,有全局身份验证管理器和本地身份验证管理器。如果需要,在配置每一个时都要特别小心。
这在全局认证管理器注释的java文档中进行了解释。
EnableGlobalAuthentication注释表示带注释的类可用于配置AuthenticationManagerBuilder的全局实例。例如:
@Configuration @EnableGlobalAuthentication公共类MyGlobalAuthenticationConfiguration { @Autowired public void configureGlobal(ADMIN auth) { AuthenticationManagerBuilder ADMIN "ADMIN");}}带有EnableGlobalAuthentication注解的注解也表示带注解的类可用于配置AuthenticationManagerBuilder的全局实例。例如:
@Configuration @EnableWebSecurity公有类管理扩展WebSecurityConfigurerAdapter { @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) { auth.inMemoryAuthentication().withUser("user").password("password").roles("USER") .and().withUser("admin").password("password").roles("USER",“AuthenticationManagerBuilder”);} //可能被覆盖的方法... }以下批注使用EnableGlobalAuthentication EnableWebSecurity EnableWebMvcSecurity EnableGlobalMethodSecurity进行批注
在没有EnableGlobalAuthentication注释的类中配置AuthenticationManagerBuilder会产生不可预知的结果。
EnableGlobalAuthentication
导入负责为全局身份验证管理器设置默认配置的配置AuthenticationConfiguration
。
AuthenticationConfiguration
配置了两个关键部分来创建身份验证管理器-用户详细信息和身份验证提供者。
使用InitializeUserDetailsBeanManagerConfigurer
配置用户详细信息,使用InitializeAuthenticationProviderBeanManagerConfigurer
配置身份验证提供程序。这两个必需的bean都是在应用程序上下文中查找的-这就是您的用户详细信息服务向全局身份验证管理器注册的方式。
GlobalMethodSecurityConfiguration
和WebSecurityConfigurerAdapter
是全局身份验证管理器的使用者。
WebSecurityConfigurerAdapter
可用于创建和配置本地身份验证管理器(添加新的身份验证提供者),通常还用于在mvc和public vs admin端点等应用程序中具有不同的身份验证/授权需求。
单独使用spring security时,@EnableWebSecurity
会触发上述流程,作为spring安全过滤器链设置的一部分。使用spring boot时,spring安全自动配置会触发相同的流程。
在spring security5.4版本中,您可以将http安全定义为bean,而不需要扩展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();
}
发布于 2020-10-28 16:57:02
您使用的是@Service
注释,它在组件扫描时创建UserDetailsService
的bean。不需要在AuthenticationManagerBuilder
中再次指定它。
如果您不使用@Service注释,那么您可以通过覆盖AuthenticationManagerBuilder
在WebSecurityConfigurerAdapter
中手动配置它。
https://stackoverflow.com/questions/64526372
复制相似问题