Scott Crowther, 软件工程师, IBM
Abe Guerra, 软件工程师, IBM
Tamer Nassar, 软件工程师, IBM
2009 年 6 月 29 日
了解如何通过用户身份验证实现一个动态的用户界面。身份验证通常是对具有多组用户的应用程序的一种要求。每个用户组都需要访问某些应用程序功能,而这部分功能对于另一个用户组可能需要进行限制。身份验证机制必须要验证用户凭证并基于用户凭证控制对应用程序功能的访问。本文展示了如何使用 OpenLDAP 和 Tomcat 实现基本的身份验证机制。本文将 OpenLDAP 和 Tomcat 实现与 OpenLDAP 和 WASCE 实现做了对比。最后,还通过例子展示了如何使用 Java™ 代码和 JSTL 实现这个动态 UI。
简介
Web 应用程序通常需要控制特定的一组用户所能使用的功能性。比如,一个应用程序可能会允许一组专业用户向应用服务器上传数据文件。但是,此应用程序需要防止一般的用户也这么做。
控制对应用程序功能的访问是一个分为两个步骤的过程。首先,使用身份验证机制来辨识当前用户。其次,使用授权机制来控制对应用程序功能的访问。此过程的实现可能会涉及到应用程序 Web 页面的多个副本,其中每组用户分别具有此 Web 页面的一个相关副本。本文建议并使用了另外一个实现,这个实现的目的是用 Web 页面的一个副本来通过 Java 和 JSTL 动态呈现适当的功能性。
实现授权的技术很多。考虑到应用程序的复杂性,本文中的实现使用了一个应用服务器。尤其是,我们使用了 Tomcat 6 和 WebSphere Application Server Community Edition 2.1 (WASCE)。之所以采用 WASCE 实现,是考虑到与 Apache Geronimo 的集成及其相关的 J2EE 平台。
本文的实现使用了 Lightweight Directory Access Protocol (LDAP)。LDAP 实现提供了一种管理应用程序用户所需的健壮机制。有若干个 LDAP 服务器可供我们使用。我们所需要的 LDAP 服务器应该是健壮、稳定和开源的。根据这些条件,我们做了一番研究,结果,OpenLDAP 成为了我们的最佳之选。
开发环境
本文针对的是一个基于 Java 的 Web 应用程序。我们使用了 Java 5、JSF 1.2 和 JSTL 1.2。我们的 IDE 是带 Web Tools Platform. (WTP) 的 Eclipse Ganymede 发行版(相关下载链接,请参见 参考资料)。
安装了 Java 和 Eclipse 之后,就可以开始设置开发环境了。首先,需要通过如下步骤创建所需的项目库:
这时的 Preferences 窗口应该类似图 1。
其次,需要通过如下步骤创建一个新的 Eclipse 项目:
|
使用 Tomcat 6
由于进行的是 Tomcat 6 和 WASCE 部署,因此我们将需要在此处分别处理不同的服务器。创建此项目的第一步是提供一个名字、目标运行时、模块版本和配置。它应类似图 2 所示(基于这种情况下的设置和 Tomcat)。
第二个步骤要求配置 Web 模块设置。在这个步骤可以包括默认设置。第三个步骤要求定义项目的 JSF Capabilities,类似于图 3。
|
安全性
现在,让我们开始定义安全性。需要定义 Web 应用程序的安全约束。我们将定义这样一种约束,这种约束将针对未经身份验证的用户保护 /WebContent/private 内的所有内容(我们将使用 UI 处理角色)。要创建这个约束,需要将清单 1 中所示代码添加到 /WebContent/WEB-INF/web.xml:
清单 1. web.xml 的示例代码
Areas with authentication required /faces/private/* * NONE |
接下来,需要定义一个登录机制。我们将定义基于表单的身份验证,并定义此表单的位置。将清单 2 中的代码添加到 web.xml:
清单 2. (接清单 1)web.xml 的示例代码
FORMLDAP/public/login.html/public/loginError.html |
我们需要对 web.xml 做的最后一个更新针对的是安全性角色。不过,由于我们通过 JSTL 处理角色,因此我们可以通过添加清单 3 中的代码来为所有角色定义约束。
清单 3. (接清单 2)web.xml 代码示例
Authenticated Users* |
为应用程序定义了安全性之后,还需要将其与一个用来管理 Web 应用程序用户的 LDAP 解决方案进行连接。可以在 /WebContent/META-INF/context.xml 中定义 LDAP 服务器。这个文件类似于清单 4。
清单 4. context.xml
|
使用 WASCE
现在,我们要用 WASCE 创建这个基于角色的导航项目。在接下来的步骤中,我们将展示如何创建并配置这个项目以及如何在 WASCE 中设置 Security LDAP。
依照以下步骤创建一个新的项目:
定义项目的 JSF 功能。请参照下面内容设定这个 JSF:
在 WASCE 中设置 Security LDAP
下面介绍如何配置 WASCE 以连接到 LDAP。LDAP 可以安装在同一个服务器上,也可以安装在不同的服务器上。只要指定了正确的连接 URL,WASCE 就能连接上它。
安全域
需要在 Security Realm 页面中输入 LDAP 信息以使 WASCE 可以与 LDAP 通信。以下是基于我们的 LDAP 设置而需要输入的字段值。
请注意:这些值可能会因您的 LDAP 设置的不同而有变化。
要完成安全性配置,需要定义一个用来保护 /WebContent/private 中所有内容的约束。要创建这个约束,可以将下面的内容添加到 web.xml:
清单 5. web.xml 中的安全性约束
FORMNot required for FORM. auth/faces/public/login.jps/faces/public/loginerror.jspAuthenticated users*Areas with authentication required/faces/private/*GETPOST* |
另外,您还需要依照清单 6 来将这个安全域添加到 geronimo-web.xml。
清单 6. geronimo-web.xml
ldap-realm |
这个项目和文件结构与 Tomcat 项目一样,其主要区别在于可以充分利用 WASCE 来进行开放 LDAP 的身份验证。
使用 WASCE 的优点
比起 Tomcat,用 WASCE 有几个优点:
|
用户界面
这个应用程序页面将存在于两个目录中。需要安全性的专用页面存在于 /WebContent/private 中。无安全性要求的公共页面存在于 /WebContent/public 中。
这个公共目录包括不要求身份验证的 html 页面,其中包括登录页面及错误页面。依照以下步骤来创建登录页面:
使用默认的身份验证机制,但它要求必须将登录表单的动作定义为 j_security_check,并使用 j_username 和 j_password。得到的 html 文件如清单 7 所示:
清单 7. 登录页面
Login
|
类似的,在公共目录中创建另一个 HTML 文件并将其命名为 loginError.html。这将是当用户试图用无效凭证登录时所显示的页面。清单 8 显示了这个页面:
清单 8. 登录错误页面
Login Error Your login attempt has failed. |
您一定还想创建一个类似的页面来显示错误消息,当一个用户请求访问他或她未被授权的功能时,就会显示错误消息。这个页面很简单,如清单 9 所示。
清单 9. 身份验证错误页面
Insert title here You are not authorized to access this functionality. |
在这个示例中,我们将使用一个简单的主页,它将模拟到应用程序功能的链接。我们还将创建 .jsp 页面,它将模拟应用程序中的不同类型的功能。所有这些文件都要被放在受保护的区域中(/WebContent/private)。这个主页将使用清单 10 中导入的标记库:
清单 10. 标记库导入
这个 .jsp 页面还使用了一个资源包以使内容可以被外部化:
这个 .jsp 页面是靠后端 Java 代码来进行用户身份验证的。一旦用户通过针对 LDAP 目录的身份验证,它们的凭证将通过 Java beans 持久化。.jsp 可以如清单 11 所示的那样引用 bean:
清单 11. Bean 引用
在上面的片段中,一个欢迎消息通过综合来自资源包(由 'msg' 引用)的内容和来自这个 Java bean(由 userBean 引用)的姓名而被显示出来。在这时,我们可以根据用户的角色开始过滤。用户的角色也包含在 Java bean 中。这让 .jsp 页面可以检查用户的角色并采取恰当的动作。例如,您可以控制基于当前的用户角色而被显示出来的功能链接。
清单 12. 角色验证
|
清单 12 中的代码片段检查当前用户的角色是否是 ‘Admin’。如果是,它将显示 admin 功能的链接。如果不是,则不显示这个链接。我们将在这个 .jsp 页面中增加额外的检查,以便模拟保护功能页面免受直接访问的功能。得到的主页应类似清单 13:
清单 13. 主页
Home |
我们将在专用目录中创建另外三个 .jsp 页面,每个页面针对一种所模拟的功能:casual、expert、admin。如我们前面提到的,我们需要在 .jsp 页面中做另一个检查来避免对 .jsp 页面的直接访问。可以按清单 14 所示内容来进行这个检查:
清单 14. 授权
在上面的代码片段中,我们检查是否有预期的用户角色。如果这个用户角色不是我们预期的,就会把用户重定向到一个错误页面。对于 casual 功能我们则不需要做这种检查,因为它对所有通过验证的用户都是开放的。
casual 功能页面应类似清单 15:
清单 15. Casual 用户功能
Insert title here Casual user functionality is accessible here. |
expert 功能页面如清单 16 所示:
清单 16. expert 用户功能
Insert title here Expert user functionality is accessible here. |
admin 功能如清单 17 所示:
清单 17. Admin 用户功能
Insert title here Admin user functionality is accessible here. |
现在的目录结构应类似下面的这个导航面板:
身份验证及持久性
出于本文的目的考虑,我们将所有后端代码放进一个程序包中,我们将这个程序包命名为 com.ibm.test。可以通过以下的步骤来创建这个程序包:
我们后面将要使用一个资源包,所以我们先依照下面的步骤来创建一个资源包:
本文中的这个示例仅为欢迎页面使用了资源包,因此,它只需下面这行代码:
welcome=Welcome |
然而,这个文件完全可以包括应用程序的所有内容。
应用程序的身份验证是由一个名为 UserBean 的 Java 类处理的。通过下面的步骤来创建它:
这个 UserBean 类将使用两个 Java 设计模式:Data Access Object (DAO) 和 Transfer Object (TO)。DAO 负责访问来自于 LDAP 目录的用户数据。TO 负责保存这些数据。UserBean 类将针对 home.jsp 的引用进行实例化:
UserBean 类的构造函数需要获取通过身份验证的用户的 ID。记住,我们正在使用的身份验证机制是 Tomcat 的默认表单身份验证。从本文的目的出发,我们将用 Tomcat 处理身份验证,并使用 UserBean 类获取并持久化通过验证的用户的数据。我们可以从 UserBean 类中获取用户 ID,见下面代码:
ExternalContext context = FacesContext.getCurrentInstance().getExternalContext(); String userID = context.getRemoteUser(); |
我们现在可以使用通过验证的用户的 ID 来从 LDAP 目录中检索所有用户数据。OpenLDAPDAO 类可实现此目的。依照以下步骤创建此类:
OpenLDAPDAO 类在类变量中包含 LDAP 目录的细节。其构造函数将会创建一个对 LDAP 目录的连接。此外,还将包含一个方法,用来检索特定用户的属性。UserBean 类通过 UserTransferObject 类保持用户数据。这个类是一个用户数据的容器。本文随附的归档文件中包含了所有类的一个副本。
这时的 Java 目录结构应该与图 11 中的导航面板结构相似。
大功告成了!不妨启动服务器并对它做个测试。
如果未通过身份验证,尝试访问主页时,将会被重定向到登录页面,如图 12 所示。
作为一个 casual 用户,登录时将只会列出功能链接中的一个,如图 13 所示。
如果用户想要直接访问 .jsp 页面上一个未被授权的功能,就会显示用户错误消息,如图 14 所示。
以 admin 身份登录时,所有功能的链接都会出现,见图 15。
|
结束语
祝贺您!在很短的时间里,您就已经建立了一个能实现授权的骨架应用程序。您现在可以围绕着这个骨架,构建一个能够基于您在 LDAP 目录中定义的用户角色控制对功能的访问的应用程序。您可以在 Tomcat 或 WASCE 上继续开发您的应用程序,还可以充分利用它的其他功能。这个应用程序骨架还实现了 JSF,本文没有对此做过多介绍,但它很值得深入研究。
值得研究的另一点是 OpenLDAP。有关设置 OpenLDAP 的内容就可以自成一篇文章了。OpenLDAP Web 站点是一个丰富的资源。第三方软件可用来协助 LDAP 服务器的管理。我们发现 Jxplorer 是一个很好的工具。不过,您可能会希望为应用程序实现一个管理部分,这样,管理员可以通过此应用程序来管理 LDAP 服务器。通过使用现有的模板加上 JSF,可以很容易地将它构建到这个应用程序骨架中去。
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/14789789/viewspace-610871/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/14789789/viewspace-610871/