Spring Security进阶——集成LDAP认证

如果对于这系列文章有疑问,可以先阅读以下链接内容(含Demo及源码下载): 
Spring Security入门篇——搭建简易权限框架: http://www.javali.org/archive/getting-start-spring-security.html  

Spring Security入门篇——集成DB认证: http://www.javali.org/archive/getting-start-spring-security-integrate-db.html  

Spring security进阶——扩展UserDetails: http://www.javali.org/archive/spring-security-advanced-extend-userdetails.html  

Spring security进阶——资源汉化(i18n): http://www.javali.org/archive/spring-security-advanced-i18n.html  


进入主题前,需要从以上链接中下载Demo工程,Spring Security提供了良好的LDAP扩展方式,基于简单的配置即可集成到你的应用里 
在simpleDemo项目pom.xml的基础上引入: 
Java代码   收藏代码
  1. <dependency>  
  2.  <groupId>org.springframework.security</groupId>  
  3.  <artifactId>spring-security-ldap</artifactId>  
  4.  <version>3.0.5.RELEASE</version>  
  5.  <type>jar</type>  
  6.  <scope>compile</scope>  
  7. </dependency>  


但是集成方式取决于LDAP存储的数据及业务系统需求,需要分两种情况考虑: 

1,LDAP服务器中存有帐号信息和角色信息 

2,LDAP服务器只存了帐号信息 

大多场合都属于后者,因为角色是由业务系统需求决定的,而LDAP在企业仅作为用户信息存储的一种方案,下面就这两种情况来看SS是怎样集成LDAP认证的 

第一种情况: 
LDAP上已经存有用户帐号及角色信息,我们只需要根据SS提供的对外接口,配置上相应的参数就行了,用户密码验证,获取角色等交给SS的LDAP扩展模块自己完成,将 security_ldap1  

覆盖SimpleDemo中的security.xml配置文件即可,建议用 Apache Directory Studio 


了解LDAP数据的内部结构后再替换红色字体部分 
Java代码   收藏代码
  1. <ldap-server  
  2.  id="myLdap"  
  3.  port="389"  
  4.  url="ldap://ldap.javali.org:389/dc=javali,dc=org"   #LDAP服务地址  
  5.  manager-dn="manager@javali.org"     #提供一个有权限访问ldap服务的帐号  
  6.  manager-password="*******" />  
  7.  <authentication-manager>  
  8.  <ldap-authentication-provider  
  9.  server-ref="myLdap"  
  10.  user-search-filter="(accountName={0})"     #ldap目录中存帐号名的节点名称  
  11.  user-search-base="OU=Users,OU=DEPARTMENT"  #用户查找base  
  12.  group-search-base="OU=Groups"  
  13.  group-role-attribute="cn"  
  14.  group-search-filter="(member={0})"      #用户所属角色的节点名称  
  15.  role-prefix="ROLE_">  
  16.  </ldap-authentication-provider>  
  17.  </authentication-manager>  


第二种情况: 

比第一种情况复杂很多,既然角色由业务系统需求决定,角色信息就保存在业务系统的数据库;处理流程应该是:LDAP负责密码认证,然后在SS- 

LDAP基础上做扩展,从DB中加载用户角色,思路是正确的,但如何扩展,如何实现,困扰了我很长时间;最后多亏了snowolf的鼎力支持(暗自庆幸身 

边有spring大牛真好) 

我们在阅读ss集成ldap源码时发现了DefaultLdapAuthoritiesPopulator类,它有一个方法签名 

Java代码   收藏代码
  1. protected Set getAdditionalRoles(DirContextOperations user, String username)  
  2.   
  3. 我想你看到方法名就应该知道它的作用了,我们就可以写一个类继承DefaultLdapAuthoritiesPopulator,在getAdditionalRoles方法里加上从数据库获取username的角色列表代码就完事了,代码如下  
  4. public class MyLdapAuthoritiesPopulator extends DefaultLdapAuthoritiesPopulator {  
  5.  public MyLdapAuthoritiesPopulator(ContextSource contextSource,  
  6.  String groupSearchBase) {  
  7.  super(contextSource, groupSearchBase);  
  8.  }  
  9.  protected Set<GrantedAuthority> getAdditionalRoles(  
  10.  DirContextOperations user, String username) {  
  11.  // 授权集合  
  12.  Set<GrantedAuthority> authorites = new HashSet<GrantedAuthority>();  
  13.  // 根据username读取用户信息  
  14.   
  15.  //TODO 根据用户信息从DB取得用户角色列表  
  16.   //将角色添加到集合里即可  
  17.  GrantedAuthority authority = new GrantedAuthorityImpl("");  
  18.  authorites.add(authority);  
  19.  return authorites;  
  20.  }  
  21. }  


此种场景只能采用Bean的配置方式 : security_ldap2  
Java代码   收藏代码
  1. <beans:bean  
  2.  id="contextSource"  
  3.  class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">  
  4.  <beans:constructor-arg  
  5.  value="ldap://ldap.javali.org:389/dc=javali,dc=org" />  
  6.  <beans:property  
  7.  name="userDn"  
  8.  value="manager@javali.org" />  
  9.  <beans:property  
  10.  name="password"  
  11.  value="******" />  
  12.  </beans:bean>  
  13.  <beans:bean  
  14.  id="ldapAuthProvider"  
  15.  class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider">  
  16.  <beans:constructor-arg>  
  17.  <beans:bean  
  18.  class="org.springframework.security.ldap.authentication.BindAuthenticator">  
  19.  <beans:constructor-arg  
  20.  ref="contextSource" />  
  21.  <beans:property  
  22.  name="userSearch">  
  23.  <beans:bean  
  24.  class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">  
  25.  <beans:constructor-arg  
  26.  value="dc=javali,dc=org" />  
  27.  <beans:constructor-arg  
  28.  value="(sAMAccountName={0})" />  
  29.  <beans:constructor-arg  
  30.  ref="contextSource" />  
  31.  </beans:bean>  
  32.  </beans:property>  
  33.  </beans:bean>  
  34.  </beans:constructor-arg>  
  35.  <beans:constructor-arg>  
  36.  <beans:bean  
  37.  id="ldapAuthoritiesPopulator"  
  38.  class="org.javali.security.ext.MyLdapAuthoritiesPopulator">  
  39.  <beans:constructor-arg  
  40.  ref="contextSource" />  
  41.  <beans:constructor-arg  
  42.  value="ou=Groups,dc=javali,dc=org" />  
  43.  </beans:bean>  
  44.  </beans:constructor-arg>  
  45.  <beans:property  
  46.  name="userDetailsContextMapper">  
  47.  <beans:bean  
  48.  id="ldapUserDetailsMapper"  
  49.  class="org.springframework.security.ldap.userdetails.LdapUserDetailsMapper">  
  50.  <beans:property  
  51.  name="rolePrefix"  
  52.  value="ROLE_" />  
  53.  <beans:property  
  54.  name="convertToUpperCase"  
  55.  value="true" />  
  56.  </beans:bean>  
  57.  </beans:property>  
  58.  </beans:bean>  
  59.  <authentication-manager>  
  60.  <authentication-provider  
  61.  ref="ldapAuthProvider">  
  62.  </authentication-provider>  
  63.  </authentication-manager>  


在配置 BindAuthenticator类时查询用户可有两种方式(可参见它的父类AbstractLdapAuthenticator),一种是 

userDnFormat,另一种是LdapUserSearch,我们采用的是第二种,使用第一种配置的时候发现它只能查找当前userDn目录下用 

户,如果有用户在更深层次就没法做到了,LdapUserSearch可以支持基于目录模糊匹配的查询方式,更强大,至少满足了我的ldap用户查询 
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
如之前所述,Spring Security 的当前版本是 5.x,没有版本号为 6 的。在 Spring Security 5.x 中,可以通过实现 `org.springframework.security.config.annotation.authentication.configurers.ldap.LdapAuthenticationProviderConfigurer` 接口来自定义 LDAP 配置。 具体步骤如下: 1. 创建一个实现了 `org.springframework.security.config.annotation.authentication.configurers.ldap.LdapAuthenticationProviderConfigurer` 接口的自定义配置类,例如 `CustomLdapAuthenticationProviderConfigurer.java`。 ```java @Configuration public class CustomLdapAuthenticationProviderConfigurer extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> implements ApplicationContextAware { private ApplicationContext context; @Override public void setApplicationContext(ApplicationContext context) throws BeansException { this.context = context; } @Override public void configure(HttpSecurity http) throws Exception { LdapContextSource contextSource = new LdapContextSource(); // 配置 LDAP 服务器连接信息 contextSource.setUrl("ldap://localhost:389"); contextSource.setBase("dc=mycompany,dc=com"); contextSource.setUserDn("cn=admin,dc=mycompany,dc=com"); contextSource.setPassword("admin"); // 配置 LDAP 认证器 BindAuthenticator authenticator = new BindAuthenticator(contextSource); authenticator.setUserSearch(new FilterBasedLdapUserSearch("ou=users", "(uid={0})", contextSource)); // 配置 LDAP 用户详细信息映射器 UserDetailsContextMapper mapper = new LdapUserDetailsMapper(); // 配置 LDAP 认证提供器 LdapAuthenticationProvider provider = new LdapAuthenticationProvider(authenticator, mapper); provider.setAuthoritiesMapper(new NullAuthoritiesMapper()); provider.setUserDetailsContextMapper(mapper); // 将自定义的 LDAP 认证提供器添加到 HttpSecurity 中 ProviderManager providerManager = new ProviderManager(Arrays.asList(provider)); http.authenticationProvider(provider); } } ``` 在上述代码中,我们通过 `LdapContextSource` 对象配置了 LDAP 服务器的连接信息,`BindAuthenticator` 对象配置了 LDAP 认证器,`LdapUserDetailsMapper` 对象配置了 LDAP 用户详细信息映射器,最后将自定义的 `LdapAuthenticationProvider` 添加到了 `HttpSecurity` 中。 2. 在 `WebSecurityConfigurerAdapter` 子类中使用自定义的 `CustomLdapAuthenticationProviderConfigurer`。 ```java @Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .anyRequest().authenticated() .and() .apply(new CustomLdapAuthenticationProviderConfigurer()); } } ``` 在上述代码中,我们将自定义的 `CustomLdapAuthenticationProviderConfigurer` 添加到了 `HttpSecurity` 中。 注意:上述代码仅供参考,具体的 LDAP 配置需要根据实际情况进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值