使用java完成ldap身份验证

转载自:http://www.cnblogs.com/lxlovezhd/archive/2013/05/29/3105350.html


一:LDAP

LDAP是Lightweight Directory Access Protocol的缩写,即轻量级目录访问协议(这个主要是相对另一目录访问协议X.500而言的;LDAP略去了x.500中许多不太常用的功能,且以TCP/IP协议为基础)。目录服务和数据库很类似,但又有着很大的不同之处。数据库设计为方便读写,但目录服务专门进行了读优化的设计,因此不太适合于经常有写操作的数据存储。同时,LDAP只是一个协议,它没有涉及到如何存储这些信息,因此还需要一个后端数据库组件来实现。这些后端可以 是bdb(BerkeleyDB)、ldbm、shell和passwd等。

LDAP目录以树状的层次结构来存储数据(类同于DNS),最顶层即根部称作“基准DN”,形如"dc=domain,dc=com"或者"o= domain.com",前一种方式更为灵活也是Windows AD中使用的方式。在根目录的下面有很多的文件和目录,为了把这些大量的数据从逻辑上分开,LDAP像其它的目录服务协议一样使用OU (Organization Unit),可以用来表示公司内部机构,如部门等,也可以用来表示设备、人员等。同时OU还可以有子OU,用来表示更为细致的分类。

LDAP中每一条记录都有一个唯一的区别于其它记录的名字DN(Distinguished Name),其处在“叶子”位置的部分称作RDN;如dn:cn=tom,ou=animals,dc=domain,dc=com中tom即为 RDN;RDN在一个OU中必须是唯一的。LDAP数据是“树”状的,这棵树是可以无限延伸的.

LDAP 其实就是一个数据库,但是跟我们平常的关系数据库有所不同。关系数据库是有一张一张的二维表格来存放数据的。ldap类似于dns系统,是树状的。用节点来存放数据。当然一个树枝可以有n个节点,每个节点上存放的数据,都是以key => value的形式。就像dns系统。 .是根,下面是com,org,net,cn等等一些树枝,这些树枝下面还有abc.com, bcd.com等等树枝。在每个树枝下面都可以放节点,其实就是域名下面的主机:www,ftp,mail等等。所有的这些内容,组成了一个dns树,在 ldap里面叫数据库。

存储LDAP配置信息及目录内容的标准文本文件格式是LDIF(LDAP Interchange Format),使用文本文件来格式来存储这些信息是为了方便读取和修改,这也是其它大多数服务配置文件所采取的格式。LDIF文件常用来向目录导入或更改记录信息,这些信息需要按照LDAP中schema的格式进行组织,并会接受schema 的检查,如果不符合其要求的格式将会出现报错信息。

在LDAP中目录是按照树型结构组织,目录由条目(Entry)组成,条目相当于关系数据库中表的记录;条目是具有区别名DN(Distinguished Name)的属性(Attribute)集合,DN相当于关系数据库表中的关键字(Primary Key);属性由类型(Type)和多个值(Values)组成,相当于关系数据库中的域(Field)由域名和数据类型组成, 只是为了方便检索的需要,LDAP中的Type可以有多个Value,而不是关系数据库中为降低数据的冗余性要求实现的各个域必须是不相关的。LDAP中条目的组织一般按照地理位置和组织关系进行组织,非常的直观。LDAP把数据存放在文件中,为提高效率可以使用基于索引的文件数据库,而不是关系数据库。LDAP协议集还规定了DN的命名方法、存取控制方法、搜索格式、复制方法、URL格式、开发接口等。LDAP对于这样存储这样的信息最为有用,也就是数据需要从不同的地点读取,但是不需要经常更新。常见的属性(Attribute)有:

二:在java中使用LDAP用于身份验证

要想在一个应用程序进入之前使用LDAP进行身份验证,在登录时后台接收要登录的用户名和密码,首先新建用于验证的类LDAPAuthentication

package com.hxkj.qrcode.action;
 
import java.util.Hashtable;
 
import javax.naming.AuthenticationException;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.Control;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;
 
public class LDAPAuthentication {
    private final String URL = "ldap://127.0.0.1:389/";
    private final String BASEDN = "ou=People,dc=example,dc=com";
    private final String FACTORY = "com.sun.jndi.ldap.LdapCtxFactory";
    private LdapContext ctx = null;
    private final Control[] connCtls = null;
 
    private void LDAP_connect() {
        Hashtable<String, String> env = new Hashtable<String, String>();
        env.put(Context.INITIAL_CONTEXT_FACTORY, FACTORY);
        env.put(Context.PROVIDER_URL, URL + BASEDN);
        env.put(Context.SECURITY_AUTHENTICATION, "simple");
         
        String root = "cn=Directory Manager";// root
        env.put(Context.SECURITY_PRINCIPAL, root);
        env.put(Context.SECURITY_CREDENTIALS, "Admin123");
        // 此处若不指定用户名和密码,则自动转换为匿名登录
        try {
            ctx = new InitialLdapContext(env, connCtls);
        } catch (javax.naming.AuthenticationException e) {
            System.out.println("验证失败:" + e.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
 
    private String getUserDN(String uid) {
        String userDN = "";
        LDAP_connect();
        try {
            SearchControls constraints = new SearchControls();
            constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
            NamingEnumeration<SearchResult> en = ctx.search("", "uid=" + uid, constraints);
            if (en == null || !en.hasMoreElements()) {
                System.out.println("未找到该用户");
            }
            // maybe more than one element
            while (en != null && en.hasMoreElements()) {
                Object obj = en.nextElement();
                if (obj instanceof SearchResult) {
                    SearchResult si = (SearchResult) obj;
                    userDN += si.getName();
                    userDN += "," + BASEDN;
                } else {
                    System.out.println(obj);
                }
            }
        } catch (Exception e) {
            System.out.println("查找用户时产生异常。");
            e.printStackTrace();
        }
 
        return userDN;
    }
 
    public boolean authenricate(String UID, String password) {
        boolean valide = false;
        String userDN = getUserDN(UID);
 
        try {
            ctx.addToEnvironment(Context.SECURITY_PRINCIPAL, userDN);
            ctx.addToEnvironment(Context.SECURITY_CREDENTIALS, password);
            ctx.reconnect(connCtls);
            System.out.println(userDN + " 验证通过");
            valide = true;
        } catch (AuthenticationException e) {
            System.out.println(userDN + " 验证失败");
            System.out.println(e.toString());
            valide = false;
        } catch (NamingException e) {
            System.out.println(userDN + " 验证失败");
            valide = false;
        }
 
        return valide;
    }
}


  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值