我为我的网页和Web服务实现了数据库身份验证.
它对两者都很好,现在我必须添加Ldap身份验证.
我必须通过远程Ldap服务器进行身份验证(使用用户名和密码),如果用户存在我必须使用我的数据库为用户角色(在我的数据库用户名是相同的用户名Ldap).
所以我必须从我的实际代码切换到Ldap和数据库认证,如上所述.我的代码是:
SecurityConfig类
它对两者都很好,现在我必须添加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{ List<GrantedAuthority> authorities = 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<GrantedAuthority> authorities) { return new User(user.getUsername(),user.getPassword(),user.isEnabled(),true,authorities); } private List<GrantedAuthority> buildUserAuthority(Set<UserRole> userRoles) { Set<GrantedAuthority> setAuths = new HashSet<GrantedAuthority>(); // Build user's authorities for (UserRole userRole : userRoles) { setAuths.add(new SimpleGrantedAuthority(userRole.getUserRoleKeys().getRole())); } List<GrantedAuthority> Result = new ArrayList<GrantedAuthority>(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) { Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>(); 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,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(); } } }
我的LDAP开发环境在Apache目录工作室中创建
解决方法
Spring Security已经支持LDAP开箱即用.它实际上有一个
whole chapter这个.
要使用和配置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来检索角色(因为只有角色在数据库中),那么可以实现自己的LdapAuthoritiesPopulator
.