我为我的网页和Web服务实现了数据库身份验证.它适用于两者,现在我必须添加Ldap身份验证.我必须通过远程Ldap服务器进行身份验证(使用用户名和密码),如果用户存在,我必须使用我的数据库作为用户角色(在我的数据库用户名中是与Ldap相同的用户名).所以我必须从我的实际代码切换到Ldap和数据库身份验证,如上所述.我的代码是:SecurityConfig类
@Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true, proxyTargetClass = true) public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired @Qualifier("userDetailsService") UserDetailsService userDetailsService; @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); } @Bean public PasswordEncoder passwordEncoder(){ PasswordEncoder encoder = new BCryptPasswordEncoder(); return encoder; } @Configuration @Order(1) public static class ApiWebSecurityConfig extends WebSecurityConfigurerAdapter{ @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .antMatcher("/client/**") .authorizeRequests() .anyRequest().authenticated() .and() .httpBasic(); } } @Configuration @Order(2) public static class FormWebSecurityConfig extends WebSecurityConfigurerAdapter{ @Override public void configure(WebSecurity web) throws Exception { web //Spring Security ignores request to static resources such as CSS or JS files. .ignoring() .antMatchers("/static/**"); } @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() //Authorize Request Configuration //the / and /register path are accepted without login //.antMatchers("/", "/register").permitAll() //the /acquisition/** need admin role //.antMatchers("/acquisition/**").hasRole("ADMIN") //.and().exceptionHandling().accessDeniedPage("/Access_Denied"); //all the path need authentication .anyRequest().authenticated() .and() //Login Form configuration for all others .formLogin() .loginPage("/login") //important because otherwise it goes in a loop because login page require authentication and authentication require login page .permitAll() .and() .logout() .logoutSuccessUrl("/login?logout") .permitAll(); // CSRF tokens handling } }
MyUserDetailsService类
@Service("userDetailsService") public class MyUserDetailsService implements UserDetailsService { @Autowired private UserServices userServices; static final Logger LOG = LoggerFactory.getLogger(MyUserDetailsService.class); @Transactional(readOnly=true) @Override public UserDetails loadUserByUsername(final String username){ try{ com.domain.User user = userServices.findById(username); if (user==null) LOG.error("Threw exception in MyUserDetailsService::loadUserByUsername : User doesn't exist" ); else{ Listauthorities = buildUserAuthority(user.getUserRole()); return buildUserForAuthentication(user, authorities); } }catch(Exception e){ LOG.error("Threw exception in MyUserDetailsService::loadUserByUsername : " + ErrorExceptionBuilder.buildErrorResponse(e)); } return null; } // Converts com.users.model.User user to // org.springframework.security.core.userdetails.User private User buildUserForAuthentication(com.domain.User user, List authorities) { return new User(user.getUsername(), user.getPassword(), user.isEnabled(), true, true, true, authorities); } private List buildUserAuthority(Set userRoles) { Set setAuths = new HashSet (); // Build user's authorities for (UserRole userRole : userRoles) { setAuths.add(new SimpleGrantedAuthority(userRole.getUserRoleKeys().getRole())); } List Result = new ArrayList (setAuths); return Result; }
所以我必须要:
1)用户从登录页面访问网页以及用户名和密码进行Web服务.这必须通过Ldap来完成.
2)用户需要数据库查询来验证用户的用户名.你知道我怎么能实现这个吗?谢谢
使用正确代码更新:关注@M.Deinum建议我创建MyAuthoritiesPopulator
类而不是MyUserDetailsService
使用数据库和Ldap进行身份验证:
@Service("myAuthPopulator") public class MyAuthoritiesPopulator implements LdapAuthoritiesPopulator { @Autowired private UserServices userServices; static final Logger LOG = LoggerFactory.getLogger(MyAuthoritiesPopulator.class); @Transactional(readOnly=true) @Override public Collection extends GrantedAuthority> getGrantedAuthorities(DirContextOperations userData, String username) { Setauthorities = new HashSet (); try{ com.domain.User user = userServices.findById(username); if (user==null) LOG.error("Threw exception in MyAuthoritiesPopulator::getGrantedAuthorities : User doesn't exist into ATS database" ); else{ for(UserRole userRole : user.getUserRole()) { authorities.add(new SimpleGrantedAuthority(userRole.getUserRoleKeys().getRole())); } return authorities; } }catch(Exception e){ LOG.error("Threw exception in MyAuthoritiesPopulator::getGrantedAuthorities : " + ErrorExceptionBuilder.buildErrorResponse(e)); } return authorities; } }
我更改了SecurityConfig,如下所示:
@Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true, proxyTargetClass = true) public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired @Qualifier("myAuthPopulator") LdapAuthoritiesPopulator myAuthPopulator; @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.ldapAuthentication() .contextSource() .url("ldap://127.0.0.1:10389/dc=example,dc=com") // .managerDn("") // .managerPassword("") .and() .userSearchBase("ou=people") .userSearchFilter("(uid={0})") .ldapAuthoritiesPopulator(myAuthPopulator); } @Configuration @Order(1) public static class ApiWebSecurityConfig extends WebSecurityConfigurerAdapter{ @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .antMatcher("/client/**") .authorizeRequests() //Excluede send file from authentication because it doesn't work with spring authentication //TODO add java authentication to send method .antMatchers(HttpMethod.POST, "/client/file").permitAll() .anyRequest().authenticated() .and() .httpBasic(); } } @Configuration @Order(2) public static class FormWebSecurityConfig extends WebSecurityConfigurerAdapter{ @Override public void configure(WebSecurity web) throws Exception { web //Spring Security ignores request to static resources such as CSS or JS files. .ignoring() .antMatchers("/static/**"); } @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() //Authorize Request Configuration //the "/" and "/register" path are accepted without login //.antMatchers("/", "/register").permitAll() //the /acquisition/** need admin role //.antMatchers("/acquisition/**").hasRole("ADMIN") //.and().exceptionHandling().accessDeniedPage("/Access_Denied"); //all the path need authentication .anyRequest().authenticated() .and() //Login Form configuration for all others .formLogin() .loginPage("/login") //important because otherwise it goes in a loop because login page require authentication and authentication require login page .permitAll() .and() .logout() .logoutSuccessUrl("/login?logout") .permitAll(); } } }
我在Apache directory studio中创建的LDAP开发环境
Spring Security已经支持LDAP开箱即用.它实际上有一整章.
要使用和配置LDAP,请添加spring-security-ldap
依赖项,然后使用它AuthenticationManagerBuilder.ldapAuthentication
来配置它.将LdapAuthenticationProviderConfigurer
允许您设置所需要的东西.
@Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.ldapAuthentication() .contextSource() .url(...) .port(...) .managerDn(...) .managerPassword(...) .and() .passwordEncoder(passwordEncoder()) .userSearchBase(...) .ldapAuthoritiesPopulator(new UserServiceLdapAuthoritiesPopulater(this.userService)); }
这样的东西(它应该至少给你一个关于什么/如何配置东西的想法)有更多选项,但检查javadocs.如果您不能使用UserService
as as来检索角色(因为只有角色在数据库中),那么LdapAuthoritiesPopulator
为此实现自己的角色.