zoukankan      html  css  js  c++  java
  • Spring Ldap user登录 userPassword验证

    Ldap  密码字段被加密,在用户登录 或者 用户更改密码时候都需要密码验证:

    1.自己的实现

    /**
     * 集成Ldap登录验证
     *
     * @author wzc
     * @date 2017年12月11日 下午2:14:37
     *
     */
    @Service
    public class LdapLogin {
        /**
         * 创建一个LdapTemplate对象
         * 连接ldap
         */
        @Autowired
        private LdapTemplate ldapTemplate;
        
         private ContextSource contextSource;  
         
    
        /**
         * 登录验证Ldap
         * @param cn   ,登录的用户名
         * @param pwd  密码
         * @return
         */
        public  boolean  loginLdap(String cn , String pwd){
            //根据cn ,构建DN
            String dn = getDnForUser(cn);
            //密码检验
            boolean result = authenticate(dn,pwd);
            return  result;
            
        }
        
         /**  
          * 根据用户名密码验证  
          * @param userCn   用户名 
          * @param pwd  密码  
          * @return  
          */    
            @SuppressWarnings("unchecked")
            public boolean authenticate(String userCn, String pwd) {   
                 DirContext ctx = null;    
                 System.out.println(userCn +":"+pwd);
                 try {    
                     //调用ldap 的 authenticate方法检验
                     boolean authenticate = ldapTemplate.authenticate(userCn, "(objectclass=person)", pwd);
                     return authenticate;    
                 } catch (Exception e) {    
                      e.printStackTrace();
                     return false;    
                 } finally {     
                     LdapUtils.closeContext(ctx);    
                 }    
          
             } 
             /**
              * 根据cn 构建出 entry 的 Dn
              * @param cn
              * @return
              */
             @SuppressWarnings({ "unused", "unchecked" })
             private String getDnForUser(String cn) {
                 
                List<String> results = ldapTemplate.search("", "(&(objectclass=person)(cn="+cn+"))",  new DnMapper());
                 
                 if (results.size() != 1) {    
                     throw new RuntimeException("User not found or not unique");    
                 }    
                 System.out.println(results.get(0));
                 return results.get(0);    
              }
    
       }
    
         /**
          * 
          * 节点的 Dn映射
          *
          * @author wzc
          * @date 2017年12月12日 上午11:21:09
          *
          */
         class DnMapper implements ContextMapper{
            @Override
            public String mapFromContext(Object ctx) {
                 DirContextAdapter context = (DirContextAdapter)ctx;
                 Name name = context.getDn();
                 String dn = name.toString();
                return dn;
            }
        }

    参考 http://angelbill3.iteye.com/blog/2321533

    如果要总结Spring的LDAP(Spring开发的操作LDAP的开源Jar),必须要从LDAP说起。
    LDAP:Lightweight Directory Access Protocol,翻译过来是轻量级目录访问协议。
    它是基于X.500标准的(X.500:构成全球分布式名录系统的协议),说的这么抽象基本上理解不了,只需要知道是一种协议,以目录的形式(结构树)来管理资原(用户、用户组、地址簿、邮件用户等)。一些大公司会选择以LDAP来存储用户及其信息。
    所以就像是数据库一般,LDAP也是有client端和server端。server端是用来存放资源,client端用来操作增删改查等操作。

    1. LDAP:Schema


    在LDAP中目录是按照树型结构组织——目录信息树(DIT)
    directory information tree (DIT).
    DIT由(Entry)组成,条目相当于关系数据库中表的记录;
    条目是具有分辨名DN(Distinguished  Name)的属性-值对(Attribute-value)的集合。(DN相当于关系型数据库表中的主键Primary key)
    关于LDAP的基础要学习的还有很多,比如客户端的安装、数据模型的学习等等。

    2. Spring LDAP


    Spring LDAP就是基于JAVA开发的LDAP客户端开源工具,主要用来操用LDAP,其实现方法有点类似Spring JdbcTemplate(这个大家都非常熟悉了~)
    支持Transaction (事务)
    支持Pooling (连接池)
    官网:http://www.springframework.org/ldap
    官方文档及例子(重要):http://docs.spring.io/spring-ldap/docs/2.1.0.RELEASE/reference/
    JAVA文档(重要):http://docs.spring.io/spring-ldap/docs/2.1.0.RELEASE/apidocs/
    GitHub(大量例子):https://github.com/spring-projects/spring-ldap

    3. 核心类:LdapTemplate


    这个类非常类似Spring JdbcTemplate,JdbcTemplate的实现是通过传入sql语句和RowMapper,query返回目标列表,或是传入sql和参数,执行update方法。JdbcTemplate的优点是简化了与数据库连接的代码(实现了ldap属性到对象的映射,使得代码更为简单和优雅),以及避免了一些常见的错误。(这个开源已经更新到4+版本了,可见其应用之广)。
    优点都是相通的,Spring LdapTemplate的优点是简化了与LDAP交互的代码(传统的类详见:
    http://docs.oracle.com/javase/7/docs/api/javax/naming/directory/package-summary.html)以及避免了一些常见的错误。

    4. 怎样理解Autherntication


    要验证一个LDAP的Entry的身份(有点类似于用户名、密码登陆),LDAP的思路是通过DN搜索到目标Entry(例如一个公司员工),那么再通过这个Entry和password来验证合法性。
    具体的业务比如是:一个员工要登陆公司网站,输入他的员工号和密码。我们是不能通过查询在LDAP里拿到用户的密码(安全性的限制),那么只能传入实际的密码,让LDAP server端验证合法性。
    ldapTemplate.authenticate(LdapQuery query, String password);
    在使用这个方法的时候曾经遇到过一个问题,如下:
    调用ldapTemplate.authenticate时验证老是通不过(always return false),经查文档发现:如果ldap连接是有连接池的话,那么总是调用已创建好的连接去验证,这样是错误的。Authenticate的验证过程需要ContextSource通过传入的待验证的用户名和密码来重新绑定生成一个连接,也就是说这个方法要使用到的connection连接并不能是连接池里的那个connection。
    所以需要new一个LdapContextSource类和LdapTemplate类,再通过LdapTemplate类的setContextSource(ContextSource contextSource)将持有用户名密码的ContextSource传入。
    注意:在contextSource创建后,需要调用afterPropertiesSet()方法来验证所有必要的参数都已经set了(特指url、用户名、密码等),这个方法执行后,真正的contextSource才会被实例化。(特别是在Spring context上下文之外的配置中,必须要执行该方法。
    这么说好像很抽象,具体代码如下:

    1.LdapContextSource contextSource = new LdapContextSource();  
    2.contextSource.setUrl(url);  
    3.contextSource.setUserDn(userDn);  
    4.contextSource.setPassword(userPwd);  
    5.contextSource.setPooled(false);  
    6.contextSource.afterPropertiesSet(); // important
    7.
    8.LdapTemplate template = new LdapTemplate();  
    9.template.setContextSource(contextSource);  
    10.
    11.Boolean result = template.authenticate(LDAP_BASE_DN, filter, pwd);

    5. Pooling
    Spring LDAP的pool用的是apache commons pool(http://commons.apache.org/proper/commons-pool/index.html
    6. 通过SSL的认证方式连接
    这块公司是用IBM的portal来安装的SSL,所以对于tomcat的配置并不是很了解。可以在stack-overflow上看看相关资料。
    【总结】
    在使用Spring ldap的一年多时间里,没有碰到太过复杂的问题,产品上线后表现也很稳定。总得来说因为跟大家都熟悉的JdbcTemplate思想上有些相似,所以学习起来成本也不高。

  • 相关阅读:
    angular安装指定版本
    Fluttter通过按钮来打开抽屉Drawer或者endDrawer
    angular中的animation动画
    flutter pubspec.yaml配置文件详解
    angular-cli卸载安装
    angular的项目基本配置的了解
    angular使用代理解决跨域
    IOS开发之UI布局
    用Objective-C写了一个简单的批量更改文件名的程序
    使用Objective-C 计算代码运行时间
  • 原文地址:https://www.cnblogs.com/Actexpler-S/p/8026962.html
Copyright © 2011-2022 走看看