获息BEA举办dev2dev原创技术文章大奖赛活动,恰巧我的项目也处于收尾验收阶段。作为Weblogic Portal8.1.2在国内的第一次大型应用,我觉得有必要把这次项目实施过程中的一些感想和经验整理成文并介绍给所有喜欢和使用Weblogic Portal的开发者。
这篇文章以解决方案集的形势收录了这次项目实施过程中对一些典型问题的解决办法。这些问题有的是Portal项目中最常遇到的,如单点登录,内容整合,有的则纯粹是解决Weblogic Portal自身问题的小技巧,如Desktop的传递中文参数的问题。
由于有太多经验和感想需要和广大Portal开发着交流,所以这个解决方案集还有必要收录更丰富的内容,这部分工作还在进行当中。希望这些来自一线的实战经验能够帮助Weblogic Portal在国内的其他项目中取得胜利。
陈龙 (dev2dev ID:SCEA)
北京有生博大软件软件技术有限公司
目录:
BEA Weblogic Portal项目实施解决方案集?来自WLP8.1 SP2在国内的第一个成功应用...
利用UUP实现Portal和已有J2EE应用的单点登录...
第二步:制作login.jsp和LoginBacking.java.
利用RSS技术实现Portal和其他Web应用的内容整合...
如果项目中有以下因素存在则有必要同步Portal和LDAP服务器的用户信息。
1. LDAP服务器为整个项目中的所有应用作集中用户身份验证服务。在这种情况下Portal不一定要和LDAP同步。因为WLS作为WLP的基础组件可以为Portal提供身份验证服务,所以只需要WLS和LDAP同步即可。具体如何在WLS中配置LDAP身份验证服务请看LDAP服务器端的配置和WLS Admin console中的配置部分。
2. Portal的用户数量众多,而且由于用户的所属的组织机构(ou)变化频繁,导致用户的角色经常变化。在这种情况下,完全有必要让Portal从LDAP服务器获取用户信息,否则开发和维护的任务将相当繁重。在Portal中为了达到基于角色的个性化,必须在Portal admin中给Portal组件指定具体的角色。让Portal 访问LDAP,从LDAP同步用户的组织机构,解决了在Portal中维护用户信息的问题,体现了LDAP作为用户身份认证服务的价值。
图1显示了目录树的组织结构,其中Groups是用于管理的环境(Context),我们用来存放groups。
Users是存放组织单元和用户的组织(Organization)。
不同的LDAP服务器配置方法各不相同,下面方法简单介绍Novell NDS的LDAP配置,所有操作都在ConsoleOne中进行:
1. 在Users下创建一个用户PortalAdmin。该用户应该是配置WLS域的管理员,用户名和密码要和其完全一致。所以建议在配置PortalDomain时选择使用PortalAdmin作为域管理员。如果需要修改PortalDomain的管理员名和密码则需要修改PortalDomain根目录下的boot.property文件,只要将username=和password=后面的密文改为明文即可,当第一次重起WLS后,系统会自动把明文以3DES算法加密。
2. 在Groups下创建两个组Administrators,PortalSystemAdministrators。
3. 将Portaladmin加入Administrators和PortalSystemAdministrators组。
4. 为PortalAdmin分配权限。也就是指定PortalAdmin为Users这个组织的受托者(Trustees)。在Users上点击右键,选择此对象的受托者(Trustees of This Object)。选择PortalAdmin,然后选择合适的权限。
5. 为了让PortalAdmin和管理环境Groups中的LDAP Group联系,还要启用明文口令。在LDAP Group上点击右键,选择属性,在一般(General)项中选择启用明文口令复选框。
用LDAP的身份验证替换WLS默认的身份验证服务需要如下配置:
1. 进入WLS admin console(需要先启动WLS),以下两种方法都可以:
2. 在admin console左侧的树型菜单依次展开Security -> Realms-> myrealm-> Providers-> Authentication。
3. 在admin console右侧页面中选择合适的目录服务的类型。我们选择Configure a new Novell Authenticator...。
4. 在新的页面中,General 面板保持默认值即可,如果有多个身份验证服务器同时存在则需要考虑Control Flag的选项。点击Create开始配置。
5. Novell LDAP 面板。这里的参数是Weblogic用来和LDAP连接的。输入的参数有:Host ,NDS服务器的IP地址;Port ,NDS的端口号,默认是389;Principal ,Weblogic用来连接NDS的用户名的DN,依照图1应该是cn=admin,o=Groups; Credential,该DN的密码。其他参数保持默认。点击Apply。
6. Users 面板。输入的参数有:User Base DN,用户的基础DN,一般为用户所属的ou的DN,如果用户分散在多个以同一o为根的ou中就需要把该值设为包含这些ou的o的DN,依照图1应该是o=Users。其他参数保持默认。点击Apply。
7. Groups 面板。输入的参数有:Group Base DN,组的基础DN,一般为管理环境的组织(o)的DN,依照图2应该是o=Groups。其他参数保持默认。点击Apply。
8. 其他的面板暂时无需配置。配置完上述参数后重新启动这个PortalDomain 的WLS,然后再次登录WLS admin console。
9. 在admin console左侧的树型菜单依次展开Security -> Realms-> myrealm-> Users 和 Security -> Realms-> myrealm-> Groups。检查上述步骤配置的结果。
10. 如果配置没有问题,WLS从LDAP获得了用户,还需要将原来的默认身份验证删除。分别是:DefaultAuthenticator,DefaultIdentityAsserter。
为了让Portal从LDAP获得用户信息,实现基于角色的个性化配置,就必须要部署一个无状态Session Bean从LDAP获得用户的信息。这个无状态Session Bean负责UUP和LDAP之间的映射。实现这个无状态Session Bean有两种方案,可以自己开发,也可以使用WLP在p13n_ejb.jar中提供的一个参考实现,com.bea.p13n.usermgmt.profile.ldap。实际上,对这个参考实现作一些配置之后就基本能够满足项目的要求。下面是具体的配置方法。ejb-jar.xml和weblogic-ejb.xml位于你的Portal应用的根目录下的p13n_ejb.jar中的META_INF目录中,application_config位于你的应用的根目录下的META_INF目录中。
1. 将p13n_ejb.jar复制到另外一个目录中。在这一新的目录中执行jar xvf p13n_ejb.jar META-INFejb-jar.xml META-INFweblogic-ejb-jar.xml命令,把p13n_ejb.jar中的META_INF目录下的ejb-jar.xml和weblogic-ejb-jar.xml解压出来。
2. 修改ejb-jar.xml。找到<!-- Ldap Property Manager 这一行,取消这一注释,使LdapPropertyManager这个无状态session bean可以部署。
3. 在LdapPropertyManager的部署描述中的多数配置和在WLS Admin console中的配置一致,见图2。
如果配置了config/principal和config/principalCredential两项,就可以将config/credentialMBeanName这一项注释或删除掉。
4. 找到<!-- User Profile Manager-->这一行,开始修改UserProfileManager的部署描述。
5. 注意下面一项:
<!-- map all properties in property set ldap to ldap server -->
<env-entry>
<env-entry-name>PropertyMapping/ldap</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>LdapPropertyManager</env-entry-value>
</env-entry>
其中PropertyMapping/ldap指明LdapPropertyManager作为ldap这个UUP中的PropertySet到LDAP服务器之间的映射,以后创建UUP文件时的名称必须和这里指定的”ldap”完全一致。
6. 修改下面一项:
<!-- an ldap property manager -->
<ejb-ref>
<ejb-ref-name>ejb/LdapPropertyManager</ejb-ref-name>
<ejb-ref-type>Session</ejb-ref-type>
<home>com.bea.p13n.property.EntityPropertyManagerHome</home>
<remote>com.bea.p13n.property.EntityPropertyManager</remote>
<!-- <ejb-link>LdapPropertyManager</ejb-link> -->
<ejb-link>EntityPropertyManager</ejb-link>
</ejb-ref>
修改为:
<!-- an ldap property manager -->
<ejb-ref>
<ejb-ref-name>ejb/LdapPropertyManager</ejb-ref-name>
<ejb-ref-type>Session</ejb-ref-type>
<home>com.bea.p13n.property.LdapPropertyManagerHome</home>
<remote>com.bea.p13n.property.LdapPropertyManager</remote>
<ejb-link>LdapPropertyManager</ejb-link>
<!-- <ejb-link>EntityPropertyManager</ejb-link> -->
</ejb-ref>
请注意home,remote接口和ejb-link的变化。
7. 按需要,可在<!-- Group profile manager -->中作同样修改。
8. 取消对
<method>
<ejb-name>LdapPropertyManager</ejb-name>
<method-name>*</method-name>
</method>
的注释。ejb-jar.xml的修改完成。
9. 修改weblogic-ejb-jar.xml文件,找到
<!-- LdapPropertyManager
<weblogic-enterprise-bean>
<ejb-name>LdapPropertyManager</ejb-name>
<enable-call-by-reference>True</enable-call-by-reference> <jndi-name>${APPNAME}.BEA_personalization.LdapPropertyManager</jndi-name>
</weblogic-enterprise-bean>
-->
取消对这一项的注释。
10. 取消对
<method>
<ejb-name>LdapPropertyManager</ejb-name>
<method-name>*</method-name>
</method>
的注释。weblogic-ejb-jar.xml的修改完成
11. META-INF中的ejb-jar.xml和weblogic-ejb-jar.xml都修改完成后,执行jar uvf p13n_ejb.jar META-INF命令,将这两个文件更新回p13n_ejb.jar中。然后将p13n_ejb.jar重新复制到Portal应用的根目录下,覆盖原始文件。
12. 修改application_config文件,在<CacheManager Name="CacheManager"></CacheManager>中加入一项:<Cache Name="ldapPropertyCache" TimeToLive="60000" Notes="Cache for UUP LDAP." MaxEntries="100"/>。该项配置同样可以在WLP admin console的Service Administration->CacheManager中添加和修改。
13. 所有的配置都完成以后,需要重新启动weblogic,并在WLS admin console中检查p13n_ejb是否部署成功。
只有创建的UUP的文件名必须和上述ejb-jar.xml中的指定的文件名完全一致,LdapPropertyManager才可以把LDAP服务器中的User的属性映射到UUP文件中定义的属性集中。
1. 在Workshop中打开你的Portal应用,在datauserprofiles下创建名为ldap.usr的属性集文件。
2. 属性集中的属性必须和LDAP服务器中的属性对应才会有意义。所以应该对照LDAP服务器中的用户属性向ldap.usr属性集中添加属性。
3. 可以去http://www.iit.edu/~gawojar/ldap/ 下载一个LDAP browser,在其中观察LDAP中User对象的属性。User对象的属性类似图3。
4. 对应的我们在ldap.usr中加入如下属性:
UUP属性集中的属性必须是LDAP服务其中User对象属性的子或全集,并且属性的类型一致。
1. 登录WLP admin console。在Workshop中打开Portal应用后在通过Portal->Portal Administration打开。
2. 用WLS域管理员身份(PortalAdmin)登陆,该WLS域管理员也是在LDAP服务器端创建的超级用户。
3. 点击Users & Groups,然后选择一个组。在右侧页面的1号区域点击Show All Users in Group,然后再2号区域点击一个用户名。
4. 在新页面中选择Edit User Profile Values标签,然后在Properties from Property Set:选择ldap。
5.
图5
在企业应用整合中,Portal负责的是表现层和部分Web Component(Portlets)层的整合。而在这些整合应用中又以单点登录(Single Sign-On)最为常见,其实SSO也最能代表Portal在应用整合中的作用。
下面介绍一个在项目中使用的简单方案,他利用一个Servlet Filter和WLP的UUP实现了Portal和项目中的其他J2EE应用通过同一个LDAP服务器进行身份验证的目的,用户只需要在Portal中登录一次,再访问其他和Portal整合的应用时无需再次登录。这个Filter只需编写一次就可以部署到多个Web项目中去,可复用程度高。
图6
FTApp是一个Portal应用。FTPortal是FTAPP这个应用下的一个Portal Web项目。RiseNet则是FTAPP这个应用下的一个普通 Web项目。之所以这样做是为了让同一个Portal应用下的项目共享一个Datasync Project,因为我们要用Datasync Project的UUP机制存取同一个用户在多个Web项目中的状态。
因为有这个限制,所以在实现单点登录之前应该把所有要整合到单点登录环境的项目导入(Import)到Portal应用中来。导入的方法是在Portal应用上点击右键然后选择Import Project。
下面开始正式的开发工作。这个过程需要创建的工件有:一个登录用的JSP页面,login.jsp,以及这个JSP页面用到的LoginBacking.java类;一个Filter,SSOFilter.java;一个UUP文件,online.usr;
在Workshop中打开你的Portal应用,在datauserprofiles下创建名为online.usr的属性集文件。在文件中加入token和password两个属性,他们的类型都是Single Unrestricted。Online.usr的作用是存取已经登录的在线用户的信息,用于以后在其他Web Project中登录。
这两个文件可以从BEA提供的例子sampleportal中导入,然后在这个基础上修改而来。他们的具体位置分别在:
%BEA_HOME%weblogic81samplesportalportalAppsampleportalportletslogin.jsp
%BEA_HOME%weblogic81samplesportalportalAppsampleportalWEB-INFsrcexamplesloginLoginBacking.java
把这两个文件导入到你的Portal项目的相应位置。根据实际需要对login.jsp做一些界面修改即可,LoginBacking.java则要加入一些额外的逻辑,这些逻辑包括用户在登录进Portal之后和退出Portal之前的操作两部分。
打开LoginBacking.java,进行如下修改:
1. 添加import com.bea.p13n.usermgmt.profile.*;
2. 找到
String username = request.getParameter("username");
String password = request.getParameter("password");
两行代码,在他们后面加入一行:
ProfileWrapper profile = ProfileFactory.getProfile(username,"everyone");
3. 找到Authentication.login(username, password, request);这一行代码。这行代码正确执行的就是用户登录Portal。在这一行之后加入我们自己的代码。我们的代码要为用户的这次登录创建一个唯一的token,然后把这个token和用户的密码一起存入online.usr中。代码示例:
代码示例1
4. 找到Authentication.logout(request);这一行代码。这行代码正确执行的结果就是用户退出Portal。在这一行之前加入我们自己的代码。代码将删除在online.usr中存储的用户登录token和password。代码示例:
代码示例2
5. 注意读者自己处理以上步骤profile操作的异常。
SSOFilter.java应该部署到每一个和Portal整合的Web项目中,他的作用是检查通过自己的Request对象,如果这个Request对应的Session没有登录就从Request对象得到token和username参数。通过username参数从online.usr中查找Portal存储的token。比较这两个token,验证用户是不是已经在Portal中登录过的合法用户。如果通过了验证,程序还要把online.usr中存储的password取出,和username一起作为这个Web应用登录的参数。在这个过程中发生任何错误都可以跳转回Portal的登录页面,如果没有错误和异常,这个Request就可以通过SSOFilter了。
代码示例3
Portal和其他Web应用内容整合的最简单方式就是使用<IFrame>,但是这种方式引发的Session同步问题在大型整合应用中往往是让人无法接受的。必须采用一种全新的整合方式,使被整合的各个应用之间达到最大程度的松耦合。因为我们整合的是内容,不涉及表现,更不涉及业务逻辑,所以XML是我们的首选。其他 Web应用把XML(内容)格式的内容信息传递给Portal,Portal使用XSLT(表现)解析XML,把XML表现为HTML(内容+表现)各式展现给用户。
为了使整合方案形成规范并符合标准,我们采用和RSS技术,它是WEB站点之间交换内容的标准。可以从BEA Portal的sampleportal例子中找到符合RSS2.0规范的XML文件(rssBEA.xml)和解析XML的XSL文件(位于rss.jsp中)。我们可以从sampleportal中导入这两个文件,然后在这个基础上修改而来。他们的具体位置分别在:
%BEA_HOME%weblogic81samplesportalportalAppsampleportalportlets ss ssBEA.xml
%BEA_HOME%weblogic81samplesportalportalAppsampleportalportlets ss ss.jsp
sampleportal演示的是如何整合外网信息,也就是整合的内容对于每个用户都是一样的,比如Yahoo的新闻等。而具体项目中的要求往往是整合的信息需要根据用户的权限和角色的不同而不同,也就是个性化的内容,如通知,待办文件,邮件列表等。这就对整合方案增加了如下要求:
1. 个性化内容整合的前提还是单点登录。必须首先实现单点登录才可以使其他Web应用为用户提供安全的,个性化的内容。
2. 从Portal发往其他Web应用的请求无需携带用户名和密码等识别用户身份的参数,因为在第一次登录这个Web应用时SSOFilter已经解决了Session的问题并且在Session中添加了识别用户身份的参数。
3. 被整合的其他Web应用需要根据用户的身份动态生成XML内容,然后把XML内容响应给发送请求的Portal。
这个过程用图说7明:
下面两图是一个整合的例子:
图8 一个模仿MSN风格的Portal界面。其中每个Portlet的内容都可能来自不同的外部应用甚至Internet。
图9 每个Portlet可以编辑自己的表现。因为我们只整合内容,不整合逻辑。内容和表现是分离的。
WL Portal的中文问题很多就是WL Server的中文问题,只有少数和Portal自身相关,但是这些问题更加隐蔽。这其中最迷惑人的就是Desktop的中文问题。
可以通过两种途径看到Portal的界面。一种是在Workshop中用Workshop Test Browser打开正在设计的portal文件,这种方式用于开发人员测试和预览Portal。另一种是在WLP Admin Console中通过Portal Management打开。这两种方式打开的Portal界面虽然相似,但是Portal后台的处理过程是完全不一样的。
这种方式我们称为”Single file mode”。这个”single file”指的就是在Portal项目中创建的扩展名是.portal的文件。这个文件其实是一个xml文件,我们用Workshop设计这个Portal文件,采用托拽等可视化操作,其实是在修改这个xml文件。在这个Portal文件上点右键,选择Open as xml,就可以看到这个Portal的本来面目了。如果鼠标右键的弹出菜单中没有,可以在Tools->Application Properties->Portal中选择is the Open as XML Option available复选框。
图10
在Workshop Test Browser中展现这个Portal的过程如下图所示:
第一步:Portal Server 首先解析.portal XML文件,从中得到这个Portal的全局配置属性,从中得知portal使用了哪些组件(shell,books,pages,layouts,menus等)。
第二步:获得这些portal组件的资源信息。
第三步:按照资源信息,定位并找到这些资源(images,javascript,CSS,JSP,HTML等)。
第四部:把所有的资源合并成HTML。
可以看出Portal Server会把.portal文件中的<portal:directive.page contentType="text/html;charset=GBK"/>这一行转换成<%@ page contentType="text/html; charset=GBK" %>用于整个Portal中的所有JSP页面,这一行的默认值是charset=UTF8。所以在测试和预览时的中文问题可以在这里解决。这个中文问题相对很好解决。
这种方式我们称为”Database mode”。这种方式用于实际的使用当中,即Portal的管理员在WLP Admin Console中根据角色把Desktop授权给相应具有权限的用户后,用户在访问自己的 Desktop时Portal Server的处理方式。显然Desktop中的中文参数传递问题不通过上述第一种方式的方法修改。
注意到这样一点,就是这种方式访问desktop的URL中包含appmanager。然后试图去Web.xml中找到和这样的URL匹配的Servlet。果然发现如下Servlet配置项:
<servlet>
<servlet-name>AppManagerServlet</servlet-name>
<servlet-class>com.bea.netuix.servlets.manager.PortalServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
和
<servlet-mapping>
<servlet-name>AppManagerServlet</servlet-name>
<url-pattern> /appmanager/* </url-pattern>
</servlet-mapping>
从AppManagerServlet所在的包路径得到线索,com.bea.netuix包负责用户界面的合成和展现。所以进一步发现com.bea.netuix.application.localization.definition.LocalizationLocale这个类(可以下载BEA Portal的API文档)。这个类中的public void setEncoding(String encoding),这个方法就是设置编码字符集的。这个类还有一个静态字符串常量public static final String DEFAULT_ENCODING,而这个变量的值是”UTF-8”。见图12。
在WLP Admin Console或Portal项目的其他配置文件中均没有发现指定其他编码字符集的方法。
我们称这种方式为”Database mode”是因为它是基于数据库的,它需要从数据库中查寻书然后合成用户界面。那么关于字符集的信息也一定存储在数据库中。根据这个思路,进行如下操作(以sampleportal为例):
1. 在Workshop中打开Tools->Weblogic Server->DataSource Viewer。见图13
图13
2. 在%BEA_HOME%weblogic81commonevalpointbase ools目录中运行startPointBaseConsole.cmd
3. 在Connect to DataBase窗口按照图12的信息添加相应选项,然后连接数据库。见图14
4. 在左侧的目录中找到SCHEMAS->WEBLOGIC->TABLES->L10N_LOCALE表。在L10N_LOCALE上点右键,选择Select * FROM “WEBLOGIC”.” L10N_LOCALE”。问题的根源一目了然。
5. 按你的要求修改Encoding,Language等字段。
其他解决方案还在整理之中,希望很快能够和大家见面。也希望您能通过Email和我联系,交流经验。
联系客服