Spring Security 3 Active Directory 身份验证、数据库授权

Posted

技术标签:

【中文标题】Spring Security 3 Active Directory 身份验证、数据库授权【英文标题】:Spring Security 3 Active Directory Authentication, Database Authorization 【发布时间】:2012-03-02 23:46:01 【问题描述】:

我正在尝试使用 AD 身份验证访问我的应用程序并从我的数据库中获取授权角色。

这是我的配置

<beans:bean id="activeDirectoryAuthenticationProvider"
        class="org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider">
    <beans:constructor-arg value="mydomain" />
    <beans:constructor-arg value="ldap://my URL :389" />
    <beans:property name="convertSubErrorCodesToExceptions" value="true"/>
</beans:bean>

我尝试添加

  <beans:constructor-arg>
    <beans:bean class="org.springframework.security.ldap.populator.UserDetailsServiceLdapAuthoritiesPopulator">
      <beans:constructor-arg ref="myUserDetailsService"/>
    </beans:bean>
  </beans:constructor-arg>

但它没有用。有什么帮助吗?

非常感谢!!

【问题讨论】:

【参考方案1】:

ActiveDirectoryLdapAuthenticationProvider 不使用LdapAuthoritiesPopulator(检查构造函数的 API)。

您可以使用委托模型,在其中包装提供者并分别加载权限,然后返回包含它们的新令牌:

public class MyAuthoritySupplementingProvider implements AuthenticationProvider 
    private AuthenticationProvider delegate;

    public MyAuthoritySupplementingProvider(AuthenticationProvider delegate) 
        this.delegate = delegate;
    

    public Authentication authenticate(Authentication authentication) 
        final Authentication a = delegate.authenticate(authentication);

        // Load additional authorities and create an Authentication object
        final List<GrantedAuthority> authorities = loadRolesFromDatabaseHere(a.getName());

        return new AbstractAuthenticationToken(authorities) 
            public Object getCredentials() 
                throw new UnsupportedOperationException();
            

            public Object getPrincipal() 
                return a.getPrincipal();
            
        ;
    

    @Override
    public boolean supports(Class<?> authentication) 
        return delegate.supports(authentication);
    

这门课是期末课,主要是因为我对 Active Directory 的基本了解以及人们想要使用它的不同方式。

【讨论】:

非常感谢。我该怎么做?我对这种技术很陌生,我找不到任何使用 ActiveDirectoryLdapAuthenticationProvider 和自定义 loadUserAuthorities 的示例 只需扩展类,调用您的数据库以获取角色并根据方法签名将它们作为List&lt;GrantedAuthority&gt; 返回。您可以使用SimpleGrantedAuthority 类来包装各个角色。 我试图扩展它,但我得到了错误:不能继承最终类 ActiveDirectoryLdapAuthenticationProvider 糟糕,抱歉。我忘记了。您必须使用委托而不是继承。我已经修改了我的答案以建议如何完成。【参考方案2】:

让我们把它分成两部分。第一个是您的 spring security xml 配置,第二部分是覆盖 spring security 提供的 UserContextMapper。

您的安全 xml 配置将是

<bean id="adAuthenticationProvider"
    class="org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider">
   <constructor-arg value="my.domain.com" />
    <constructor-arg value="ldap://<adhostserver>:<port>/" />
    <property name="convertSubErrorCodesToExceptions" value="true" />
    <property name="userDetailsContextMapper" ref="myUserDetailsContextMapper" />
</bean>

<bean id="myUserDetailsContextMapper" class="com.mycompany.sme.workflow.controller.MyDbAuthorizationFetcher">
<property name="dataSource" ref="dataSource" />

MyDbAuthorizationFetcher 是您将在其中实现 UserContextMapper 类以从 DB 获取权限的类

public class MyDbAuthorizationFetcher implements UserDetailsContextMapper 

private JdbcTemplate jdbcTemplate;
@Autowired
private DataSource dataSource;

public JdbcTemplate getJdbcTemplate() 
    return jdbcTemplate;


public void setJdbcTemplate(JdbcTemplate jdbcTemplate) 
    this.jdbcTemplate = jdbcTemplate;


public DataSource getDataSource() 
    return dataSource;


public void setDataSource(DataSource dataSource) 
    this.dataSource = dataSource;


// populating roles assigned to the user from AUTHORITIES table in DB
private List<SimpleGrantedAuthority> loadRolesFromDatabase(String username) 

    DbRole role = new DbRole();
    String sql = "select * from user where user_id = ?";
    jdbcTemplate = new JdbcTemplate(getDataSource());
    role = jdbcTemplate.queryForObject(sql, new Object[]  username , new DbRoleMapper());


    try 
        dataSource.getConnection().setAutoCommit(true);
     catch (SQLException e) 

    
    List<SimpleGrantedAuthority> authoritiess = new ArrayList<SimpleGrantedAuthority>();
    SimpleGrantedAuthority auth = new SimpleGrantedAuthority(String.valueOf(role.getRoleId()));
    authoritiess.add(auth);
    return authoritiess;

   

@Override
public UserDetails mapUserFromContext(DirContextOperations ctx,
        String username, Collection<? extends GrantedAuthority> authorities) 

    List<SimpleGrantedAuthority> allAuthorities = new ArrayList<SimpleGrantedAuthority>();
      for (GrantedAuthority auth : authorities) 
        if (auth != null && !auth.getAuthority().isEmpty()) 
           allAuthorities.add((SimpleGrantedAuthority) auth);
        
      
      // add additional roles from the database table
      allAuthorities.addAll(loadRolesFromDatabase(username));
      return new User(username, "", true, true, true, true, allAuthorities);


@Override
public void mapUserToContext(UserDetails user, DirContextAdapter ctx) 
    // TODO Auto-generated method stub



【讨论】:

我认为这是更简洁的解决方案,如果您需要,它还可以让您访问用户的 AD 属性。【参考方案3】:

需要在AbstractAuthenticationToken中将authenticated flag设置为true,除非它不认为是成功

【讨论】:

以上是关于Spring Security 3 Active Directory 身份验证、数据库授权的主要内容,如果未能解决你的问题,请参考以下文章

Spring Security 3 Active Directory 身份验证、数据库授权

通过 Active Directory LDAP 使用 Spring-Security 进行身份验证

Spring Security Active Directory 错误凭据处理(错误 49)

Spring Security Active Directory LDAP 身份验证错误

具有 Active Directory 和数据库角色的 Spring Security

Spring Security - 在Spring Boot中针对LDAP使用Active Directory对用户进行身份验证