【IT168 技术文章】
采用HTTP基本的验证的例子
http基本验证是Web客户端验证的一种,它和系统的授权机制一起控制受保护资源的访问。
步骤:
1. 创建一个j2ee应用
在应用程序部署工具的File菜单选中New子菜单中的Application菜单项(见图1)。会弹出新建应用程序对话框。填写应用程序文件名和应用程序显示名(见图2)。
图1

图2

2. 创建一个web组件
在应用程序部署工具的File菜单选中New子菜单中的Web Compent菜单项,会弹出新建web组件向导对话框(见图3)。选择Create New WAR File in Application,在下拉框中选择步骤1创建的应用test,在WAR Display Name框中填写WebAppTest.点击Content栏中的Eidt按钮选择此Web组件包含的文件。在这个例子中只有一个webtest.jsp文件。然后点击Next,进入下一个对话框(见图4)。由于我们的web组件是一个jsp文件,因此在组件类型中选择JSP。然后一直按Next直到结束。此时我们已经创建了一个只包含一个jsp文件的web组件。接下来是配置安全属性的步骤。
图3

图4

3. 配置安全属性
3.1创建安全角色
在部署工具的左导航栏中点中步骤2创建的web组件WebAppTest,在右边的属性页中选择Roles属性页(见图5)。点击Add按钮,在Name栏中填写安全角色名user,Description栏填写描述信息。安全角色代表具有相同安全权限用户的集合。
图5

3.2 配置安全策略
创建了安全角色后,应该对安全角色配置相应的安全策略。点击Security属性页(见图6)。
图6

首先选择你想用的验证方式,从User Authentication Method下拉框中选择Basic。这意味着你将通过基本的HTTP验证方式验证用户。下面我们进行web资源的授权。点击Security Constraint栏中的Add按钮添加一条安全约束,约束名可以自定。接下来对创建好的约束添加Web资源。首先在Web Resource Collections中添加资源集合,然后选取资源集合包含的资源。此例中WRCollection资源集合中包含webtest.jsp文件,也可以包含各种属于这个web组件的文件。接下来选择哪些web操作要收到约束,j2sdkee1.3.1中只包含两种操作(GET和POST),不同的产品支持的操作有所不同,在开发是应结合具体产品提供的操作来选取。现在应该指定安全角色了,点击Authorized Roles栏中的Edit按钮,会弹出安全角色列表对话框,从中选取已定义的安全角色。本例中选择user。至此安全策略已经配置完毕,下面的步骤是将实际环境中的用户和用户组映射与安全角色进行映射。
4. 映射
在左导航栏中选中应用程序test在右边选择Security属性页(见图7),在Role Name Reference栏中选中user,点击正下方的Add按钮,会弹出用户和用户组列表对话框,从中选择要映射成安全角色user的用户或组。此例中我们将用户j2ee映射为安全角色user。这样用户J2ee将具有为安全角色user分配的访问授权。
图7

5. 部署应用
选中Web Context属性页,在Context Root文本框中填写test,右键点击左导航栏的应用test,在弹出菜单中选择deploy完成应用程序的发布。至此我们完成了第一个例子的全部步骤。
部署描述文件
这个例子使用了说明性的安全服务,因此我们不需要编写任何的安全相关的代码,而是完全通过配置组件的部署描述文件来实现的。下面是这个web组件的部署描述文件。
2 <!DOCTYPE web-app PUBLIC
3 '-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN'
4 'http://java.sun.com/dtd/web-app_2_3.dtd'>
5 <web-app>
6 <display-name>WebAppTest</display-name> //Web组件名称
7 <servlet>
8 <servlet-name>webtest</servlet-name>
9 <display-name>webtest</display-name>
10 <jsp-file>/webtest.jsp</jsp-file> //组件中包含的jsp文件
11 </servlet>
12 <session-config>
13 <session-timeout>30</session-timeout>
14 </session-config>
15 <security-constraint> //安全约束部分
16 <web-resource-collection> //受约束的web资源集
17 <web-resource-name>WRCollection</web-resource-name> //资源集名
18 <url-pattern>/webtest.jsp</url-pattern> //资源的url表达式
19 <http-method>GET</http-method> //受约束的资源操作方法
20 <http-method>POST</http-method>
21 </web-resource-collection>
22 <auth-constraint> //对安全角色授权
23 <role-name>user</role-name> //安全角色名
24 </auth-constraint>
25 <user-data-constraint>
26 <transport-guarantee>NONE</transport-guarantee>
27 </user-data-constraint>
28 </security-constraint>
29 <login-config> //验证方式设置
30 <auth-method>BASIC</auth-method> //使用基本的HTTP验证方式
31 <realm-name></realm-name>
32 </login-config>
33 <security-role> //定义安全角色
34 <description>this is a user</description>
35 <role-name>user</role-name>
36 </security-role>
37 </web-app>
38
从部署描述文件可以知道这是一个名为WebAppTest的web组件,包含一个名为webtest.jsp的文件,只有被赋予user安全角色的用户或用户组才有权对webtest.jsp进行GET或POST操作。这里并没有包含安全角色对实际用户的映射,j2ee部署描述文件的DTD中并没有定义用于安全角色和实际用户的映射的元素,因为实际环境中有多种不同的用户系统(如关系数据库,系统文件形式和LDAP系统等)。因此安全角色和实际用户的映射方式是由j2ee产品厂商制定的。
测试运行结果
打开ie,在导航栏输入http://localhost:8000/test/webtest.jsp回车,会弹出验证对话框,要求用户提供用户名和密码(见图8),输入用户名j2ee和密码j2ee。通过用户验证后执行jsp文件,webtest.jsp打印出"hello!"(见图9)。
图8

图9

注释:在第一个例子中已经详细的描述了各个步骤,在接下来的例子中会有一些与第一个例子相同的操作,因此对下面的例子只描述与第一个例子不同的步骤。
基于表单的验证的例子
基于表单的验证与基本的HTTP验证的唯一区别是基本的HTTP验证用浏览器提供的验证信息对话框收集用户验证信息,而基于表单的验证允许自定义登陆页面来收集用户验证信息。本例子与第一个例子的步骤基本相同,不同的地方在于此例子要提供登陆页面和出错页面。
登陆页面login.html
2 <input type=text name="j_username">
3 <input type=password name="j_password">
4 <input type=submit name="login" value="login">
5 </form>
6
此文件有几个地方值得注意:
Action的值必须为"j_security_check"
获取用户名的域名必须是"j_username"
获取用户密码的域必须是" j_password"
出错页面 error.html
2 用户名或密码不正确!
3 </html>
4
出错页面只是简单的显示出错信息。
配置基于表单的验证
首先将login.html和error.html加入到WebAppTest组件中。
然后见图10选择Security属性页,在User Authentication Method下拉框中选择Form Based选项。点击Settings…弹出用户验证设置对话框,在Login Page下拉框选login.html,在Error Page下拉框选error.html。
图10

重新部署应用,再一次访问http://localhost:8000/test/webtest.jsp 会出现login页面(见图11),如果用户名或密码错误,error.html将显示给用户。
图11

部署描述文件
2 <!DOCTYPE web-app PUBLIC
3 '-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN'
4 'http://java.sun.com/dtd/web-app_2_3.dtd'>
5 <web-app>
6 <display-name>WebAppTest</display-name>
7 .
8 .
9 .
10 <transport-guarantee>NONE</transport-guarantee>
11 </user-data-constraint>
12 </security-constraint>
13 <login-config>
14 <auth-method>FORM</auth-method> //使用基于表单的验证方式
15 <realm-name>Default</realm-name> //使用缺省的安全域
16 <form-login-config>
17 <form-login-page>/login.html</form-login-page> //定义登陆页面
18 <form-error-page>/error.html</form-error-page> //定义出错页面
19 </form-login-config>
20 </login-config>
21 <security-role>
22 <description>this is a user</description>
23 <role-name>user</role-name>
24 </security-role>
25 </web-app>
从j2ee1.3开始便提供了对ejb的方法进行授权的安全服务,这种授权服务由ejb容器实现。当调用者调用ejb的方法时,ejb容器用调用者的身份来查找授予此调用者的访问权限条目,如果调用者调用的方法属于授权条目,那么ejb容器调用方法。否则,ejb容器拒绝调用此方法,并向调用者返回拒绝访问异常。可以对远程方法和home接口方法进行授权。本例中我们将对一个远程方法和一个home接口方法进行授权。
2
3 远程接口 Count.java
4
5 import javax.ejb.*;
6
7 import java.rmi.RemoteException;
8
9 public interface Count extends EJBObject {
10
11 /**
12
13 * 远程方法count
14
15 */
16
17 public int count() throws RemoteException;
18
19 }
20
21 Home接口 CountHome.java
22
23 import javax.ejb.*;
24
25 import java.rmi.RemoteException;
26
27 /**
28
29 * This is the home interface for CountBean.
30
31 * One create() method is in this Home Interface, which
32
33 * corresponds to the ejbCreate() method in the CountBean file.
34
35 */
36
37 public interface CountHome extends EJBHome {
38
39 /*
40
41 * This method creates the EJB Object.
42
43 *
44
45 * @param val Value to initialize counter to
46
47 *
48
49 * @return The newly created EJB Object.
50
51 */
52
53 Count create(int val) throws RemoteException, CreateException;
54
55 }
56
57 实现类 CountBean.java
58
59 import javax.ejb.*;
60
61 import java.security.Principal;
62
63 /**
64
65 public class CountBean implements SessionBean {
66
67 // The current counter is our conversational state.
68
69 public int val;
70
71 private SessionContext sessionCtx;
72
73 //
74
75 // 远程商业方法实现
76
77 public int count() {
78
79 System.out.println("count()");
80
81 return ++val;
82
83 }
84
85 //
86
87 // home接口Create方法的实现
88
89 //
90
91 public void ejbCreate(int val) throws CreateException {
92
93 this.val = val;
94
95 System.out.println("ejbCreate()");
96
97 }
98
99 public void ejbRemove() {
100
101 System.out.println("ejbRemove()");
102
103 }
104
105 public void ejbActivate() {
106
107 System.out.println("ejbActivate()");
108
109 }
110
111 public void ejbPassivate() {
112
113 System.out.println("ejbPassivate()");
114
115 }
116
117 public void setSessionContext(SessionContext ctx) {
118
119 sessionCtx=ctx;
120
121 }
122
123 }
124
125 客户端程序 CountClient.java
126
127 import javax.ejb.*;
128
129 import javax.naming.*;
130
131 import java.util.Properties;
132
133 /**
134
135 * This class is a simple example of client code.
136
137 */
138
139 public class CountClient {
140
141 public static void main(String[] args) {
142
143 try {
144
145 InitialContext ctx = new InitialContext();
146
147 CountHome home = (CountHome)
148
149 javax.rmi.PortableRemoteObject.narrow(
150
151 ctx.lookup("java:comp/env/CountHome"), CountHome.class);
152
153 int countVal = 0;
154
155 Count count=null;
156
157 /*
158
159 创建并执行远程方法
160
161 */
162
163 System.out.println("Instantiating beans...");
164
165 count = home.create(countVal);
166
167 countVal = count.count();
168
169 System.out.println(countVal);
170
171 /*
172
173 remove Count对象
174
175 */
176
177 count.remove();
178
179 } catch (Exception e) {
180
181 System.out.println(e.getMessage());
182
183 e.printStackTrace();
184
185 }
186
187 }
188
189 }
190
191
这个ejb包括一个远程商业方法count(),我们将将此方法授权给某个安全角色。此外还将home接口的Create()方法授权给安全角色。
步骤1
编译以上源程序并用j2sdkee1.3.1的组装发布工具(deploytool.bat)进行组装(如图12)。
图12

步骤2:配置安全角色
在对方法进行授权前,必须创建将被授权的安全角色。创建安全角色的步骤前边已经介绍过了,此处不再重复。本例中我们创建名为admin的安全角色。
步骤3:方法授权
方法授权的过程是确定那些安全角色可以访问特定方法的过程。方法授权一般是应用程序组装或应用程序部署者的责任。他们根据企业特定的需求创建不同的安全角色,并授予这些安全角色特定的访问权限。
用鼠标选中CountBean,在右端的窗口选择Security属性页(如图13),在Security Identity选项中选择Use Caller ID,这意味着ejb容器将用方法调用者的身份来验证方法调用权限。 Run As Specified Role选项将在"传播调用者身份标识的例子"进行介绍。由于在前面创建了admin安全角色,因此你可以看到Method Permissions栏中出现admin列。首先对远程方法count()进行授权。选择Remote选项,并在count()方法的Availability列中选择Sel Roles,然后选中count()方法的admin列。到此为止我们已对远程方法count()进行了授权。接下来对home接口的create()方法进行授权。在Show栏中选择Remote Home,剩下的步骤与count()方法授权相同。我们已经将count()方法和create()方法授权给了admin安全角色。但安全角色这是一个逻辑的集合,并不代表具体的用户或用户组,因此结下来我们要做的就是将安全角色与实际的用户映射起来。
步骤4:角色映射
首先我们需要在我们的j2ee环境中创建一个用户,用户起名为Tony,密码为1。
图13

这里我们使用用户名和密码的方式进行身份验证。我们在default Realm中创建此用户。可以使用命令行方式:"realmtool -add Tony 1 eng"。详细的使用方法参见j2sdk1.3.1文档的工具部分。接下来映射安全角色到用户。选中ejb应用CountEjb,在右边窗口中选择Security属性页(如图14),点击Edit Roles按钮,选择安全角色admin。再点击Add按钮选择Tony用户。这样已经将安全角色admin和用户Tony映射起来了。
步骤5:部署应用
部署应用到本地机,右键点击ejb应用CountEjb,选择弹出菜单的deploy项,按要求配置各项。
步骤6:创建客户端
创建客户端将客户端程序的主类和其他辅助类打包。创建端将客的过程比较简单,这里就不作描述了。
步骤7:运行程序
现在可以运行客户端程序来验证方法的授权了。通过命令runclient.bat -client客户端jar包文件名 -name 主类名来执行客户端程序。客户端程序的容器将显示一个对话框来提示用户输入用户名和密码(如图15),填写用户名和密码,按OK。
图15

若用户名或密码与授权的方法不符,则会抛出没有权限异常(如图16)。
图16

Countejb的部署描述文件ejb.xml
2 <!DOCTYPE ejb-jar PUBLIC
3 '-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN'
4 'http://java.sun.com/dtd/ejb-jar_2_0.dtd'>
5 <ejb-jar>
6 <display-name>count</display-name>
7 <enterprise-beans>
8 <session> // CountBean属于session bean
9 <display-name>CountBean</display-name> //ejb组件的显示名
10 <ejb-name>CountBean</ejb-name> //ejb组件名
11 <home>CountHome</home> //Home接口
12 <remote>Count</remote> //远程接口
13 <ejb-class>CountBean</ejb-class> //实现类
14 <session-type>Stateful</session-type> // CountBean属于Stateful Bean
15 <transaction-type>Container</transaction-type> //CountBean事务类型为容器管理的
16 <security-identity> //安全标识
17 <description></description>
18 <use-caller-identity></use-caller-identity> //CountBean使用调用者的身份标识
19 </security-identity>
20 </session>
21 </enterprise-beans>
22 <assembly-descriptor>
23 <security-role>
24 <role-name>admin</role-name> //定义安全角色admin
25 </security-role>
26 <method-permission> //将方法count和remove授权给安全角色admin
27 <role-name>admin</role-name>
28 <method> //方法定义
29 <ejb-name>CountBean</ejb-name>
30 <method-intf>Remote</method-intf>
31 <method-name>count</method-name>
32 <method-params />
33 </method>
34 <method>
35 <ejb-name>CountBean</ejb-name>
36 <method-intf>Home</method-intf>
37 <method-name>remove</method-name>
38 <method-params>
39 <method-param>java.lang.Object</method-param>
40 </method-params>
41 </method>
42 </method-permission>
43 <method-permission>
44 <unchecked /> //不检查以下方法的授权
45 <method>
46 <ejb-name>CountBean</ejb-name>
47 <method-intf>Remote</method-intf>
48 <method-name>getHandle</method-name>
49 <method-params />
50 </method>
51 .
52 .
53 .
54 .
55 <method>
56 <ejb-name>CountBean</ejb-name>
57 <method-intf>Remote</method-intf>
58 <method-name>getEJBHome</method-name>
59 <method-params />
60 </method>
61 </method-permission>
62 <container-transaction> // CountBean的事务属性
63 <method>
64 <ejb-name>CountBean</ejb-name>
65 <method-intf>Remote</method-intf>
66 <method-name>count</method-name>
67 <method-params />
68 </method>
69 <trans-attribute>Required</trans-attribute>
70 </container-transaction>
71 </assembly-descriptor>
72 </ejb-jar>
73
此例程包括两个部分,分别演示可编程安全性和调用者身份传播。
可编程安全性例程
可编程安全性可应用在web层和EJB层,分别是通过javax.servlet.http.HttpServletRequest接口的isUserInRole ()、getUserPrincipal ()方法和javax.ejb.EJBContext接口的isCallerInRole ()、getCallerPrincipal ()方法来实现的。 public boolean isUserInRole(java.lang.String role)方法此方法用来判断调用者是否属于某一特定的安全角色,如果属于返回true,否则返回false。参数role指定某一安全角色。通过此方法开发者可以在程序代码中加入自己的安全逻辑判断,从而增强了J2EE在安全方面的灵活性。
public java.security.Principal getUserPrincipal()方法调用此方法可以得到一个java.security.Principal对象,此对象包含了调用者的用户名,通过Principal.getName()方法可以得到用户名。通过调用getUserPrincipal()方法开发者可以得到调用者的用户名,然后对调用者的用户名进行特定的逻辑判断。
public java.security.Principal getCallerPrincipal()方法 和public boolean isCallerInRole(java.lang.String roleName)方法的作用和方法同上。
下面我们通过例程来演示这些方法的用法
程序清单:
2 <html>
3 <head><title>JSP Page</title></head>
4 <body>
5 <%-- <jsp:useBean id="beanInstanceName" scope="session" class="package.class" /> --%>
6 <%-- <jsp:getProperty name="beanInstanceName" property="propertyName" /> --%>
7 Hello!
8 the caller is <%=request.getUserPrincipal().getName()%><br/> <%--得到调用者的用户名--%>
9 <% if (request.isUserInRole("admin")){%> <%--判断调用者是否属于"admin"安全角色--%>
10 the caller is admin Role;
11 <%} %>
12 </body>
13 </html>
14 web.xml
15 <?xml version="1.0" encoding="UTF-8"?>
16 <!DOCTYPE web-app PUBLIC
17 '-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN'
18 'http://java.sun.com/dtd/web-app_2_3.dtd'>
19 <web-app>
20 <display-name>WebApp</display-name>
21 <servlet>
22 <servlet-name>webtest</servlet-name>
23 <display-name>webtest</display-name>
24 <jsp-file>/webtest.jsp</jsp-file>
25 <security-role-ref>
26 <role-name>adminref</role-name>
27 <role-link>admin</role-link>
28 </security-role-ref>
29 <security-role-ref>
30 <role-name>guestref</role-name>
31 <role-link>guest</role-link>
32 </security-role-ref>
33 </servlet>
34 <session-config>
35 <session-timeout>30</session-timeout>
36 </session-config>
37 <welcome-file-list>
38 <welcome-file>webtest.jsp</welcome-file>
39 </welcome-file-list>
40 <security-constraint>
41 <web-resource-collection>
42 <web-resource-name>WRCollection</web-resource-name>
43 <url-pattern>/webtest.jsp</url-pattern>
44 <http-method>GET</http-method>
45 <http-method>POST</http-method>
46 </web-resource-collection>
47 <auth-constraint>
48 <role-name>admin</role-name>
49 <role-name>guest</role-name>
50 </auth-constraint>
51 <user-data-constraint>
52 <transport-guarantee>NONE</transport-guarantee>
53 </user-data-constraint>
54 </security-constraint>
55 <login-config>
56 <auth-method>BASIC</auth-method>
57 <realm-name></realm-name>
58 </login-config>
59 <security-role>
60 <role-name>admin</role-name>
61 </security-role>
62 <security-role>
63 <role-name>guest</role-name>
64 </security-role>
65 </web-app>
66
从web.xml文件的内容可以看出,只有安全角色为"admin"和"guest"的用户才有权对webtest.jsp文件进行POST和GET操作。
运行结果:
创建一个web应用,将webtest.jsp作为一个web组件,并按照web.xml的内容配置web应用,在运行环境中将用户j2ee分配为admin安全角色,将用户Tony分配为guest角色。发布web应用到本地j2ee Server上。用ie访问webtest.jsp 如图17用用户j2ee的身份进行验证,用户j2ee属于admin安全角色。显示结果见图18
图17

图18

如果用用户Tony进行验证,结果见图19
图19

ejb中应用可编程的安全性与在web中的方法相似,本文不再进行介绍
传播调用者身份标识例程
本例程将演示调用者身份标识如何在调用链中传递的,并且介绍如何应用"Run As"来实现在调用链中更改调用者的身份。本例将用一个web组件(一个jsp文件)和两个ejb组件来形成一个调用链。
程序清单:
webtest.jsp
2 <%@page import="andy.*"%>
3 <%@page import="javax.naming.*"%>
4 <html>
5 <head><title>JSP Page</title></head>
6 <body>
7 <%-- <jsp:useBean id="beanInstanceName" scope="session" class="package.class" /> --%>
8 <%-- <jsp:getProperty name="beanInstanceName" property="propertyName" /> --%>
9 Hello!
10 the caller is <%=request.getUserPrincipal().getName()%> <br/>
11 <% if (request.isUserInRole("admin")){%>
12 the caller is admin Role;
13 <%} %>
14 <%
15 try {
16 Context ctx = new InitialContext();
17 andy.CountHome home =
18 (andy.CountHome)javax.rmi.PortableRemoteObject.narrow(
19 ctx.lookup("java:comp/env/CountHome"), andy.CountHome.class);
20 andy.Count count = home.create(1);
21 count.count();
22 }catch (Exception e)
23 {
24 e.printStackTrace();
25 }
26 %>
27 </body>
28 </html>
29
CountBean.java
2 import javax.ejb.*;
3 import javax.naming.*;
4 public class CountBean implements SessionBean {
5 public int val;
6 private SessionContext EjbCxt = null;
7 public int count()
8 {
9 int temp = 0;
10 System.out.println("CountBean.count()");
11 //打印调用者名
12 System.out.println("the caller is "+EjbCxt.getCallerPrincipal().getName());
13 //判断调用者的安全角色
14 if(EjbCxt.isCallerInRole("adminref")) // adminref为安全角色admin的引用名
15 {
16 System.out.println("the caller is admin Role");
17 }
18 if(EjbCxt.isCallerInRole("guestref")) // guestref为安全角色guest的引用名
19 {
20 System.out.println("the caller is guest Role");
21 }
22 if(EjbCxt.isCallerInRole("userref")) // userref为安全角色user的引用名
23 {
24 System.out.println("the caller is user Role");
25 }
26 //调用另一个ejb的远程方法
27 try {
28 Context ctx = new InitialContext();
29 CountHome1 home =
30 (CountHome1)javax.rmi.PortableRemoteObject.narrow(
31 ctx.lookup("java:comp/env/CountHome1"), CountHome1.class);
32 Count1 count = home.create(1);
33 temp = count.count();
34 }catch (Exception e)
35 {
36 e.printStackTrace();
37 }
38 return ++temp;
39 }
40 public void ejbCreate(int val) throws CreateException {
41 this.val = val;
42 }
43 public void ejbRemove() {
44 }
45 public void ejbActivate() {
46 }
47 public void ejbPassivate() {
48 }
49 public void setSessionContext(SessionContext ctx) {
50 EjbCxt = ctx; //获取EjbContext对象
51 }
52 }
53 CountBean1.java
54 package andy;
55 import javax.ejb.*;
56 public class CountBean1 implements SessionBean {
57 public int val;
58 private SessionContext EjbCxt = null;
59 public int count() {
60 System.out.println("CountBean1.count()");
61 System.out.println("the caller is "+EjbCxt.getCallerPrincipal().getName());
62 if(EjbCxt.isCallerInRole("adminref"))
63 {
64 System.out.println("the caller is admin Role");
65 }
66 if(EjbCxt.isCallerInRole("guestref"))
67 {
68 System.out.println("the caller is guest Role");
69 }
70 if(EjbCxt.isCallerInRole("userref"))
71 {
72 System.out.println("the caller is user Role");
73 }
74
75 return ++val;
76 }
77 public void ejbCreate(int val) throws CreateException {
78 this.val = val;
79 }
80 public void ejbRemove() {
81 }
82 public void ejbActivate() {
83 }
84 public void ejbPassivate() {
85 }
86 public void setSessionContext(SessionContext ctx) {
87 EjbCxt = ctx;
88 }
89 }
90
以上的三个文件分别是一个web组件和两个ejb组件的源代码,这三个组件构成了一个调用链.webtest.jsp中,首先通过HttpServletRequest..getUserPrincipal ()方法来得到调用webtest.jsp的用户的Principal对象,在通过Principal.getName()方法得到调用者的用户名. 然后通过HttpServletRequest..isUserInRole()方法来判断调用这是否属于特定的安全角色.CountBean是一个stateful SessoinBean,它拥有一个count()远程方法,在这个远程方法中写了用于得到调用者用户名和判断调用这安全角色的代码,还包括调用CountBean1对象的代码,用于展示调用者身份标识是如何在调用链中传递和调用者的安全角色如何被改变的.CountBean1也是一个stateful SessoinBean,它的代码内容与CountBean基本相同,只不过它不包含调用其他Bean的代码.
现在我们应该配置各组件的安全属性了.我们在组件webtest中创建安全角色admin,引用名为adminref,在组件CountBean和CountBean1中分别创建安全角色admin和user, 引用名分别为adminref和userref.将webtest组件配置为"HTTP Basic Authentication",给安全角色admin赋予访问webtest.jsp的权限.把CountBean设置为Run As Specified Role,选择user安全角色.在运行环境中将用户j2ee赋予admin安全角色和user安全角色.然后发布应用到服务器.用用户j2ee访问webtest.jsp.
执行结果:
客户端见图20
图20

服务器端:
CountBean.count()
the caller is j2ee
the caller is admin Role
CountBean1.count()
the caller is j2ee
the caller is user Role
从运行结果看,访问webtest.jsp的用户为j2ee,其安全角色为admin,访问CountBean的用户名为j2ee,安全角色为admin.可以看到用户身份标识从web容器传递到了ejb容器.再看组件CountBean1的输出结果,由于CountBean被设置成了Run As Specified Role,因此在CountBean向下调用其他组件对象时,用户安全角色已经被改为指定的安全角色,这里是user.所以我们会看到,调用组件CountBean1的用户名为j2ee,安全角色为user.j2ee的这种安全特性满足了同一用户在不同应用中具有不同安全角色的需求.开发人员也可以利用这种特性进行灵活的安全逻辑判断.