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思想上有些相似,所以学习起来成本也不高。

时间: 2024-08-30 10:55:33

Spring Ldap user登录 userPassword验证的相关文章

单点登录CAS与Spring Security集成(数据库验证,向客户端发送更多信息)

准备工作 CAS server从网上直接下载下来,里面有一个cas-server-webapp的工程,使用Maven命令构建,导入到Eclipse中,便可以直接使用,cas server我使用的是3.5.2版本.客户端,我是使用以前的工程,只要是Web工程就行,cas-client使用的3.2.1,Spring Security使用的是3.1.4,记得Spring Security的3.1.2版本和CAS集成时,当需要CAS Server传比较多的信息给客户端时,客户端的Spring Secur

SpringMVC+Apache Shiro+JPA(hibernate)案例教学(二)基于SpringMVC+Shiro的用户登录权限验证

序: 在上一篇中,咱们已经对于项目已经做了基本的配置,这一篇文章开始学习Shiro如何对登录进行验证. 教学: 一.Shiro配置的简要说明. 有心人可能注意到了,在上一章的applicationContext.xml配置文件中,包含以下配置. <!-- 項目自定义的Realm --> <bean id="shiroDbRealm" class="org.shiro.demo.service.realm.ShiroDbRealm" ><

Spring+MyBatis实践—登录和权限控制

1.实现用户登录功能: 通过session来实现用户登录功能.在用户登录时,将用户的相关信息放在HttpSession对象用,其中HttpSession对象可以通过HttpServletRequest的getSession方法获得.同时,HttpSession对象对应Jsp内置对象session,在jsp页面中也可以通过session来访问,如通过jstl标签库来访问session中的内容: <c:if test="${sessionScope.username == null}"

Spring+MyBatis实践——登录与权限控制

Spring+MyBatis实践--登录与权限控制 1.实现用户登录功能: 通过session来实现用户登录功能.在用户登录时,将用户的相关信息放在HttpSession对象用,其中HttpSession对象可以通过HttpServletRequest的getSession方法获得.同时,HttpSession对象对应Jsp内置对象session,在jsp页面中也可以通过session来访问,如通过jstl标签库来访问session中的内容: Html代码   <c:if test="${

Spring Security 自定义登录认证(二)

一.前言 本篇文章将讲述Spring Security自定义登录认证校验用户名.密码,自定义密码加密方式,以及在前后端分离的情况下认证失败或成功处理返回json格式数据 温馨小提示:Spring Security中有默认的密码加密方式以及登录用户认证校验,但小编这里选择自定义是为了方便以后业务扩展,比如系统默认带一个超级管理员,当认证时识别到是超级管理员账号登录访问时给它赋予最高权限,可以访问系统所有api接口,或在登录认证成功后存入token以便用户访问系统其它接口时通过token认证用户权限

(四)SSO之CAS框架单点登录,修改验证数据库的方式

应需求的变化,在登录cas的时候,默认根据用户名和密码进行验证,如果加上用户名,密码和一个系统标识进行验证呢?该如何做呢? 我们知道cas默认的登录界面中,输入的用户名和密码,再配置一下deployerConfigContext.xml 这个文件中的bean  org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler 的这个标签,写上对应的sql,以及在<bean id="dataSource" class=&q

MVC5 网站开发之六 管理员功能之登录、验证和注销

上次业务逻辑和展示层的架构都写了,可以开始进行具体功能的实现,这次先实现管理员的登录.验证和注销功能.   一.业务逻辑层 1.实现256散列加密方法. Ninesky.Core[右键]-> 添加->文件夹,输入文件夹名General. General文件夹[右键]->添加->类,输入类名Security. 引用System.Security.Cryptography命名空间(1),并实现SHA256静态加密方法. 2.Administrator模型类 Ninesky.Core[右

基于Spring LDAP和Spring Security的用户认证和权限控制Web实现

利用LDAP服务,使用Spring LDAP,Spring Security实现Web项目用户认证和简单的权限控制.实现多系统账号统一. 1.基于EHR的LDAP用户信息 LDAP是轻量目录访问协议,英文全称是Lightweight Directory Access Protocol,一般都简称为LDAP.LDAP目录以树状的层次结构来存储数据.如果你对自顶向下的DNS树或UNIX文件的目录树比较熟悉,也就很容易掌LDAP目录树这个概念了.就象DNS的主机名那样,LDAP目录记录的标识名(Dis

springMVC中实现用户登录权限验证

通过上网搜资料显示,使用filter和interceptor都可以实现.不过推荐使用interceptor. 下面就使用Interceptor实现用户登录权限验证功能. 拦截器需要实现Inceptor拦截器接口的三个方法. 1.preHandle方法,顾名思义,该方法将在请求处理之前进行调用.SpringMVC 中的Interceptor 是链式的调用的,在一个应用中或者说是在一个请求中可以同时存在多个Interceptor .每个Interceptor 的调用会依据它的声明顺序依次执行,而且最