无法将java.lang.String强制转换为org.springframework.security.ldap.userdetails.LdapUserDetails

时间:2019-01-17 19:52:57

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

我设法配置了OAuth2和ldap授权。通过实现 LdapUserDetails CustomUserDetailsContextMapper 通过实现 UserDetailsContextMapper 创建自定义 LdapUser 。 最终,通过Active Directory用户名和密码进行授权时,我会获得访问令牌。

但是问题是,我无法从 SecurityContextHolder.getContext()。getAuthentication()中获取当前登录的用户 java.lang.String无法强制转换为LdapUser

在我的安全配置下面:

@Override
  protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(adAuthenticationProvider())
        .ldapAuthentication()
    .userSearchBase("ldap.searchbase").userSearchFilter("ldap.filter").groupSearchFilter("ldap.groupsearch")
        .contextSource(contextSource())
        .userDetailsContextMapper(userDetailsContextMapper())
        .passwordCompare()
        .passwordEncoder(new LdapShaPasswordEncoder())
        .passwordAttribute("userPassword");
  }

@Bean
public DefaultSpringSecurityContextSource contextSource() {
    return  new DefaultSpringSecurityContextSource(Arrays.asList("ldap.url"), "dc=smth,dc=com");
 }

  @Bean
public ActiveDirectoryLdapAuthenticationProvider adAuthenticationProvider() {
ActiveDirectoryLdapAuthenticationProvider provider = new ActiveDirectoryLdapAuthenticationProvider("smth.com","ldap.url");
    provider.setConvertSubErrorCodesToExceptions(true);
    provider.setUseAuthenticationRequestCredentials(true);
    provider.setUserDetailsContextMapper(userDetailsContextMapper());
    return provider;
}

@Bean
  public UserDetailsContextMapper userDetailsContextMapper() {
    return new CustomUserDetailsContextMapper();
  }

自定义LdapUser:

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.ldap.userdetails.LdapUserDetails;
import java.util.Collection;

public class LdapUser implements LdapUserDetails
{
    private String commonName;
    private LdapUserDetails ldapUserDetails;

public LdapUser(LdapUserDetails ldapUserDetails) {
    this.ldapUserDetails = ldapUserDetails;
}

@Override
public String getDn() {
    return ldapUserDetails.getDn();
}

@Override
public void eraseCredentials() {

}

@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
    return ldapUserDetails.getAuthorities();
}

@Override
public String getPassword() {
    return ldapUserDetails.getPassword();
}

@Override
public String getUsername() {
    return ldapUserDetails.getUsername();
}

@Override
public boolean isAccountNonExpired() {
    return ldapUserDetails.isAccountNonExpired();
}

@Override
public boolean isAccountNonLocked() {
    return ldapUserDetails.isAccountNonLocked();
}

@Override
public boolean isCredentialsNonExpired() {
    return ldapUserDetails.isCredentialsNonExpired();
}

@Override
public boolean isEnabled() {
    return ldapUserDetails.isEnabled();
}
}

CustomUserDetailsContextMapper: 我可以成功打印出上下文属性,并且看到这是我的登录用户

@Configuration
public class CustomUserDetailsContextMapper extends LdapUserDetailsMapper implements UserDetailsContextMapper {
private LdapUser ldapUser = null;
private String commonName;
private Boolean isCity;

@Override
public LdapUserDetails mapUserFromContext(DirContextOperations ctx, String username, Collection<? extends GrantedAuthority> authorities) {
    Attributes attributes = ctx.getAttributes();
    LdapUserDetails ldapUserDetails = (LdapUserDetails) super.mapUserFromContext(ctx,username,authorities);
    return new LdapUser(ldapUserDetails);
}

@Override
public void mapUserToContext(UserDetails user, DirContextAdapter ctx) {

    }
}

现在这就是我想要获取自定义LdapUser的方式:

public LdapUser getCurrentLdapUser() {
    org.springframework.security.core.context.SecurityContext securityContext = SecurityContextHolder
            .getContext();
    Authentication authentication = securityContext.getAuthentication();
    LdapUser user = null;
    if (authentication != null) {
            user = ((LdapUser) authentication.getPrincipal());
    }
    return user;
}

调用此函数后,出现转换错误。当我尝试获取主体名称时,它将返回-username。我不知道为什么它没有返回我LdapUser

1 个答案:

答案 0 :(得分:1)

好的,我知道了。错过了基本的东西。 由于我没有配置资源服务器( ResourceServerConfigurerAdapter ),因此每个登录的Active Directory用户都被视为匿名用户。这就是为什么安全上下文返回String用户而不是我的自定义Ldap用户。

这是示例 ResourceServerConfig ,以防有人需要:

@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

  private static final String RESOURCE_ID = "resource_id";

  @Override
  public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources
    .resourceId(RESOURCE_ID)
    .stateless(false);
  }

  @Override
  public void configure(HttpSecurity http) throws Exception {
    http
    .anonymous().disable()
    .authorizeRequests()
    .antMatchers("/api/**").hasAnyAuthority("Authority_1","Authority_2")
    .and().exceptionHandling().authenticationEntryPoint(new UnauthorizedHandler())
    .and().exceptionHandling().accessDeniedHandler(accessDeniedHandler());
  }

  @Bean
  public AccessDeniedHandler accessDeniedHandler() {
    return new CustomAccessDeniedHandler();
  }
}