首先,这两种方法用于不同的目的并且不能互换。
Case 1:
UserDetailsService
纯粹用作 DAO,通过您的身份验证来定位用户信息,并根据该信息对用户进行身份验证,不应在内部进行任何身份验证UserDetailsService
,只是数据访问。
规格清楚地提到了这一点。这就是您正在寻找的。
Case2:
AuthentictionProvider
另一方面用于提供自定义的身份验证方法,例如,如果您想在登录名和密码以外的字段上进行自定义身份验证,您可以通过实现来实现AuthentictionProvider
并将这个对象提供给您AuthenticationManagerBuilder
。我认为这不是您想要在项目中做的事情。您只是希望使用默认方式的登录名和密码根据存储在数据库中的用户来实现身份验证。
在上面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 http://docs.spring.io/spring-security/site/docs/4.0.0.RC1/reference/htmlsingle/#tech-userdetailsservice
评论后:您可以设置PasswordEncoder
在您的配置方法中,无需太多麻烦即可执行以下操作:
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);
}
@Bean
public PasswordEncoder passwordEncoder(){
PasswordEncoder encoder = new BCryptPasswordEncoder();
return encoder;
}
您可以这样做,因为您可以访问AbstractDaoAuthenticationConfigurer
从返回auth.userDetailsService(userDetailsService)
它允许你配置DaoAuthenticationProvider
,这是您选择使用时选择的提供商UserDetailsService
。
你是对的PasswordEncoder
安顿好了AuthenticationProvider
但你不必
实施AuthenticationProvider
只需使用从返回的 convinence 对象auth.userDetailsService(userDetailsService)
并在该对象上设置编码器,将其传递给AuthenticationPriovider
在你的情况下DaoAuthenticationProvider
那是已经为你创建的。
就像评论中提到的走鹃一样,您很少需要实现自己的AuthenticationProvider
通常大多数身份验证配置调整都可以通过使用来完成AbstractDaoAuthenticationConfigurer
如上所述,它是从返回的auth.userDetailsService(userDetailsService)
.
“如果我想添加密码加密。如果我想进行其他身份验证(例如检查用户是否被锁定、活动、用户是否仍然登录等[不包括密码哈希])将使用身份验证提供者。”
不,这是作为标准身份验证机制的一部分为您完成的http://docs.spring.io/autorepo/docs/spring-security/3.2.0.RELEASE/apidocs/org/springframework/security/core/userdetails/UserDetails.html http://docs.spring.io/autorepo/docs/spring-security/3.2.0.RELEASE/apidocs/org/springframework/security/core/userdetails/UserDetails.html如果你看一下界面UserDetails
您将看到,如果上述任何方法返回错误,身份验证都会失败。
实施AuthenticationProvider
在非常非标准的情况下确实需要。该框架几乎涵盖了所有标准内容。