如果对于这系列文章有疑问,可以先阅读以下链接内容(含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代码  

springboot LDAP ad域认证 spring security ldap教程_spring



    1. <dependency>  
    2.  <groupId>org.springframework.security</groupId>  
    3.  <artifactId>spring-security-ldap</artifactId>  
    4. 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代码  

    springboot LDAP ad域认证 spring security ldap教程_spring



      1. <ldap-server  
      2. "myLdap"
      3. "389"
      4. "ldap://ldap.javali.org:389/dc=javali,dc=org"
      5. "manager@javali.org"
      6. "*******"
      7.  <authentication-manager>  
      8.  <ldap-authentication-provider  
      9. "myLdap"
      10. "(accountName={0})"
      11. "OU=Users,OU=DEPARTMENT"
      12. "OU=Groups"
      13. "cn"
      14. "(member={0})"
      15. "ROLE_">  
      16.  </ldap-authentication-provider>  
      17.  </authentication-manager>




      第二种情况: 



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



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



      边有spring大牛真好) 



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



      Java代码  

      springboot LDAP ad域认证 spring security ldap教程_spring



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




      此种场景只能采用Bean的配置方式 :

      security_ldap2

       


      Java代码  

      springboot LDAP ad域认证 spring security ldap教程_spring



        1. <beans:bean  
        2. "contextSource"
        3. class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">  
        4.  <beans:constructor-arg  
        5. "ldap://ldap.javali.org:389/dc=javali,dc=org"
        6.  <beans:property  
        7. "userDn"
        8. "manager@javali.org"
        9.  <beans:property  
        10. "password"
        11. "******"
        12.  </beans:bean>  
        13.  <beans:bean  
        14. "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. "contextSource"
        21.  <beans:property  
        22. "userSearch">  
        23.  <beans:bean  
        24. class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">  
        25.  <beans:constructor-arg  
        26. "dc=javali,dc=org"
        27.  <beans:constructor-arg  
        28. "(sAMAccountName={0})"
        29.  <beans:constructor-arg  
        30. "contextSource"
        31.  </beans:bean>  
        32.  </beans:property>  
        33.  </beans:bean>  
        34.  </beans:constructor-arg>  
        35.  <beans:constructor-arg>  
        36.  <beans:bean  
        37. "ldapAuthoritiesPopulator"
        38. class="org.javali.security.ext.MyLdapAuthoritiesPopulator">  
        39.  <beans:constructor-arg  
        40. "contextSource"
        41.  <beans:constructor-arg  
        42. "ou=Groups,dc=javali,dc=org"
        43.  </beans:bean>  
        44.  </beans:constructor-arg>  
        45.  <beans:property  
        46. "userDetailsContextMapper">  
        47.  <beans:bean  
        48. "ldapUserDetailsMapper"
        49. class="org.springframework.security.ldap.userdetails.LdapUserDetailsMapper">  
        50.  <beans:property  
        51. "rolePrefix"
        52. "ROLE_"
        53.  <beans:property  
        54. "convertToUpperCase"
        55. "true"
        56.  </beans:bean>  
        57.  </beans:property>  
        58.  </beans:bean>  
        59.  <authentication-manager>  
        60.  <authentication-provider  
        61. "ldapAuthProvider">  
        62.  </authentication-provider>  
        63.  </authentication-manager>




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



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



        户,如果有用户在更深层次就没法做到了,LdapUserSearch可以支持基于目录模糊匹配的查询方式,更强大,至少满足了我的ldap用户查询