我使用了jhipster 5.7和spring security 5
我有一个通过LDAP对用户进行身份验证的安全配置。这样很好 但现在我想使用另一个AuthenticationProvider(使用多种身份验证机制)。
这表示在LDAP和我的数据库身份验证之间切换,如果未通过,请首先检查LDAP身份验证。
我使用了以下代码:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
@Import(SecurityProblemSupport.class)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
CustomAuthenticationProvider customAuthProvider;
private final AuthenticationManagerBuilder authenticationManagerBuilder;
private final UserDetailsService userDetailsService;
private final TokenProvider tokenProvider;
private final CorsFilter corsFilter;
private final SecurityProblemSupport problemSupport;
public SecurityConfiguration(AuthenticationManagerBuilder authenticationManagerBuilder, UserDetailsService userDetailsService, TokenProvider tokenProvider, CorsFilter corsFilter, SecurityProblemSupport problemSupport) {
this.authenticationManagerBuilder = authenticationManagerBuilder;
this.userDetailsService = userDetailsService;
this.tokenProvider = tokenProvider;
this.corsFilter = corsFilter;
this.problemSupport = problemSupport;
}
@PostConstruct
public void init() {
try {
authenticationManagerBuilder
.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
} catch (Exception e) {
throw new BeanInitializationException("Security configuration failed", e);
}
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers(HttpMethod.OPTIONS, "/**")
.antMatchers("/app/**/*.{js,html}")
.antMatchers("/i18n/**")
.antMatchers("/content/**")
.antMatchers("/swagger-ui/index.html")
.antMatchers("/test/**");
}
@Override
public void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class)
.exceptionHandling()
.authenticationEntryPoint(problemSupport)
.accessDeniedHandler(problemSupport)
.and()
.headers()
.frameOptions()
.disable()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/api/register").permitAll()
.and()
.apply(securityConfigurerAdapter());
}
private JWTConfigurer securityConfigurerAdapter() {
return new JWTConfigurer(tokenProvider);
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@InjectService
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.ldapAuthentication()
.userSearchBase("..") //don't add the base
.userSearchFilter("...")
.contextSource(getContextSource());
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Bean
public LdapContextSource getContextSource() {
LdapContextSource contextSource = new LdapContextSource();
contextSource.setUrl("...");
contextSource.setBase("....");
contextSource.setUserDn("...);
contextSource.setPassword("..");
contextSource.afterPropertiesSet(); .
return contextSource;
}
}
然后我创建CustomAuthenticationProvider:
@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
LdapAuthenticationProvider provider = null;
private static final Logger log = LoggerFactory.getLogger(CustomAuthenticationProvider.class);
private final UserRepository userRepository;
@Autowired
private final LdapContextSource ldapContextSource;
public CustomAuthenticationProvider(UserRepository userRepository, LdapContextSource ldapContextSource) {
this.userRepository = userRepository;
this.ldapContextSource = ldapContextSource;
}
@Override
public Authentication authenticate(Authentication authentication) {
log.debug("AUTHENTICATION Login" + authentication.getName());
log.debug("AUTHENTICATION Password" + authentication.getCredentials().toString());
BindAuthenticator bindAuth = new BindAuthenticator(ldapContextSource);
FilterBasedLdapUserSearch userSearch = new FilterBasedLdapUserSearch(
"", "(sAMAccountName={0})",
ldapContextSource);
try{
bindAuth.setUserSearch(userSearch);
bindAuth.afterPropertiesSet();
} catch (Exception ex) {
java.util.logging.Logger.getLogger(CustomAuthenticationProvider.class.getName()).log(Level.SEVERE, null, ex);
}
provider = new LdapAuthenticationProvider(bindAuth);
provider.setUserDetailsContextMapper(new UserDetailsContextMapper() {
@Override
public UserDetails mapUserFromContext(DirContextOperations ctx, String username, Collection<? extends GrantedAuthority> clctn) {
Optional<User> isUser = userRepository.findOneWithAuthoritiesByLogin(username);
final User user = isUser.get();
Set<Authority> userAuthorities = user.getAuthorities();
Collection<GrantedAuthority> grantedAuthorities = new ArrayList<>();
for(Authority a: userAuthorities){
GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(
a.getName());
grantedAuthorities.add(grantedAuthority);
}
return new org.springframework.security.core.userdetails.User(
username, "1" , grantedAuthorities);
}
@Override
public void mapUserToContext(UserDetails ud, DirContextAdapter dca) {
}
});
return provider.authenticate(authentication);
}
@Override
public boolean supports(Class<?> auth) {
return auth.equals(CustomAuthenticationProvider.class);
}
}
但是始终使用此代码仅检查DB身份验证。
当我删除以下行时:
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
我遇到此错误:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.security.authentication.AuthenticationManager' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1506)
有人可以帮助我在身份验证中使用多个提供程序吗