Spring-boot LDAP自定义UserDetails

时间:2015-03-12 10:47:50

标签: spring spring-security ldap spring-boot spring-security-ldap

我在spring-boot应用程序中使用LDAP身份验证(基于注释的配置)。我想自定义UserDetails对象。默认UserDetails实现是 LdapUserDetailsImpl 。我想扩展这个类,并添加一些额外的iterfaces并绑定到spring-security。 我的配置类:

@Configuration
protected static class AuthenticationConfiguration extends GlobalAuthenticationConfigurerAdapter { 
    @Autowired
    private UserService userService;
    @Autowired
    private Environment env;

    @Override
    public void init(AuthenticationManagerBuilder auth) throws Exception {
        AuthMethod authMethod = AuthMethod.valueOf(env.getRequiredProperty("auth_method"));
        switch (authMethod) {
            case LDAP:
                auth.ldapAuthentication()
                    .userDnPatterns(env.getRequiredProperty("ldap.user_dn_patterns"))
                    .groupSearchBase(env.getRequiredProperty("ldap.group_search_base"))
                    .contextSource()
                    .url(env.getRequiredProperty("ldap.url"));
                break;
            default:
                auth.userDetailsService(userService);
                break;
        }

    }

    @Bean
    public LdapContextSource contextSource () {
        LdapContextSource contextSource= new LdapContextSource();
        contextSource.setUrl(env.getRequiredProperty("ldap.url"));
        contextSource.setUserDn(env.getRequiredProperty("ldap.user"));
        contextSource.setPassword(env.getRequiredProperty("ldap.password"));
        contextSource.afterPropertiesSet();
        return contextSource;
    }
}

UserService是自定义身份验证方法(它是数据库/ jpa身份验证)。 UserDetails访问器(当auth方法是LDAP时,它返回LdapUserDetailsImpl对象):

    @Component("activeUserAccessor")
public class ActiveUserAccessorImpl implements ActiveUserAccessor
{
    public UserDetails getActiveUser()
    {
        return (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    }
}

感谢您的帮助。

1 个答案:

答案 0 :(得分:18)

我的解决方案:

1.创建自定义UserDetailsContextMapper:

    @Bean
    public UserDetailsContextMapper userDetailsContextMapper() {
        return new LdapUserDetailsMapper() {
            @Override
            public UserDetails mapUserFromContext(DirContextOperations ctx, String username, Collection<? extends GrantedAuthority> authorities) {
                UserDetails details = super.mapUserFromContext(ctx, username, authorities);
                return new CustomLdapUserDetails((LdapUserDetails) details, env);
            }
        };
    }

2.使用LdapAuthenticationProviderConfigurer绑定UserDetailsContextMapper:

  auth.ldapAuthentication()
      .userDetailsContextMapper(userDetailsContextMapper())
      .userDnPatterns(env.getRequiredProperty("ldap.user_dn_patterns"))
      .groupSearchBase(env.getRequiredProperty("ldap.group_search_base"))
      .contextSource()
      .url(env.getRequiredProperty("ldap.url"));

3.Implement CustomLdapUserDetails(现在只更改了isEnabled方法)。您可以在CustomUserAccessor.getActiveUser()中添加一些额外的接口,方法到CustomLdapUserDetails并返回扩展类。

public class CustomLdapUserDetails implements LdapUserDetails {
private static final long serialVersionUID = 1L;

private LdapUserDetails details;
private Environment env;

public CustomLdapUserDetails(LdapUserDetails details, Environment env) {
    this.details = details;
    this.env = env;
}

public boolean isEnabled() {
    return details.isEnabled() && getUsername().equals(env.getRequiredProperty("ldap.username"));
}

public String getDn() {
    return details.getDn();
}

public Collection<? extends GrantedAuthority> getAuthorities() {
    return details.getAuthorities();
}

public String getPassword() {
    return details.getPassword();
}

public String getUsername() {
    return details.getUsername();
}

public boolean isAccountNonExpired() {
    return details.isAccountNonExpired();
}

public boolean isAccountNonLocked() {
    return details.isAccountNonLocked();
}

public boolean isCredentialsNonExpired() {
    return details.isCredentialsNonExpired();
}
}