首先,这两种方法用于不同的目的,不可互换。
案例一:
UserDetailsService 纯粹用作 DAO,通过您的身份验证来定位用户信息,并根据该信息验证用户身份,不应在 UserDetailsService 内进行身份验证,只需访问数据。
规范清楚地提到了这一点。这就是你要找的。p>
案例2:
另一方面,AuthentictionProvider 用于提供自定义的身份验证方法,例如,如果您想对登录名和密码以外的字段进行自定义身份验证,您可以通过实现 AuthentictionProvider 并将此对象提供给您的 @ 987654327@。我不认为这是你想在你的项目中做的。您只是希望使用默认方式的登录名和密码基于存储在数据库中的用户来实现您的身份验证。
在上面的 Case 1 中,您仅实现了 UserDetailsService,AuthentictionProvider 的实例是由容器在 AuthenticationManager 中为您创建的,它是 DaoAuthenticationProvider,因为您提供了 UserDetailsService,这不过是系统中用于检索用户进行身份验证的 DAO。
现在开始实施,
在您的配置中,而不是:
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// auth.userDetailsService(new AdminSecurityService());
auth.authenticationProvider(new AdminSecurityAuthenticationProvider());
}
做这样的事情
@Autowired
private CustomUserDetailsService userDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
你的CustomUserDetailsService 必须实现org.springframework.security.core.userdetails.UserDetailsService
@Service
public class CustomUserDetailsService implements UserDetailsService {
private final AdminRepository userRepository;
@Autowired
public CustomUserDetailsService(AdminRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Admin user = userRepository.findByLogin(username);
if (user == null) {
throw new UsernameNotFoundException(String.format("User %s does not exist!", username));
}
return new UserRepositoryUserDetails(user);
}
private final static class UserRepositoryUserDetails extends Admin implements UserDetails {
private static final long serialVersionUID = 1L;
private UserRepositoryUserDetails(User user) {
super(user);
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return AuthorityUtils.createAuthorityList("ROLE_USER");
}
@Override
public String getUsername() {
return getLogin();//inherited from user
}
@Override
public boolean isAccountNonExpired() {
return true;//not for production just to show concept
}
@Override
public boolean isAccountNonLocked() {
return true;//not for production just to show concept
}
@Override
public boolean isCredentialsNonExpired() {
return true;//not for production just to show concept
}
@Override
public boolean isEnabled() {
return true;//not for production just to show concept
}
//getPassword() is already implemented in User.class
}
}
当然实现取决于您,但您必须能够提供用户密码,以及该接口中基于检索到的用户(在您的情况下为 Admin.class)中的其余方法。希望能帮助到你。我没有运行这个例子,所以如果我有一些错别字,请继续询问是否有问题。如果您不需要它,我也会从您的项目中删除“AuthentictionProvider”。
这里有文档:http://docs.spring.io/spring-security/site/docs/4.0.0.RC1/reference/htmlsingle/#tech-userdetailsservice
在 cmets 之后:
您可以在您的配置方法中设置PasswordEncoder,而无需太多麻烦,只需这样做:
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);
}
@Bean
public PasswordEncoder passwordEncoder(){
PasswordEncoder encoder = new BCryptPasswordEncoder();
return encoder;
}
您可以这样做,因为您可以访问从auth.userDetailsService(userDetailsService) 返回的AbstractDaoAuthenticationConfigurer,并且它允许您配置DaoAuthenticationProvider,这是您选择使用UserDetailsService 时的首选提供商。
你是对的 PasswordEncoder 设置在 AuthenticationProvider 但你不必
实现AuthenticationProvider 只需使用从auth.userDetailsService(userDetailsService) 返回的convineince 对象并将您的编码器设置在该对象上,该对象将在您的情况下将其传递给AuthenticationPriovider,DaoAuthenticationProvider 已经为您创建。
就像评论中提到的 roadrunner 一样,您很少需要实现自己的AuthenticationProvider,通常大多数身份验证配置调整都可以使用AbstractDaoAuthenticationConfigurer 来完成,如上所述,auth.userDetailsService(userDetailsService) 是从auth.userDetailsService(userDetailsService) 返回的。
“如果我想添加密码加密。如果我想进行其他身份验证(例如检查用户是否被锁定、活动、用户是否仍在登录等 [不包括密码哈希])将使用 AuthenticationProvider。”
不,这是作为标准身份验证机制的一部分为您完成的
http://docs.spring.io/autorepo/docs/spring-security/3.2.0.RELEASE/apidocs/org/springframework/security/core/userdetails/UserDetails.html
如果您查看接口UserDetails,您将看到如果上述任何方法返回错误身份验证将失败。
在非常不标准的情况下确实需要实现AuthenticationProvider。该框架几乎涵盖了所有标准内容。