安全性对于企业环境非常重要。在 Java EE 5 / GlassFish 环境中,您可以通过以下几种方式实现安全性:
- 传输层安全性 (TLS) / 安全套接字层 (SSL) 技术
- 身份验证 (Authentication) 和授权 (Authorization)
- 消息层安全性(仅适用于 GlassFish 中的 Web 服务)
本文讨论身份验证和授权。参考资料 [1]、[2] 和 [3] 讨论了如何在客户端和服务器端为 Enterprise JavaBeans 和 Web 服务建立 SSL 环境。Web 服务的消息层安全性将在以后的文章中讨论。
身份验证服务一般通过要求用户输入用户名和密码来实现校验用户身份的目的。在 Java EE 环境中,身份验证是和域(realm)相关联的。域可以通过多种方式存储用户身份信息,包括文件、LDAP 目录、甚至是通过 JDBC 访问的数据库(请参阅 参考资料 [4])。它还可以与 Solaris 可拔插验证模块 (Pluggable Authentication Modules, PAM) 框架一起工作。
授权服务根据所运行的软件和运行该软件的用户的身份来执行访问控制授权操作。每次当用户登录时,应用程序都会为他/她赋予一组权限。
在 Java EE 5 之前,如果您希望在某个应用程序使用授权,则需要在应用程序部署描述符 ejb-jar.xml 或 web.xml
中指定授权信息。Java EE 5 的重要改进之一就是简化了 Java EE 应用程序的开发。从 Java EE 5 开始,开发人员可以在
Java 源文件中指定注释,而无需在部署描述符中加入元数据。注释简化了 Java EE 应用程序的开发,缩短了开发周期,并降低了总体拥有成本。
JSR 250(请参阅 参考资料 [5])定义了 Java 平台中的常用注释。本文将讨论 JSR 250 中定义的安全注释,并演示如何在应用程序中通过它们来实现身份验证和授权,以获得安全性。
目录
注释 (Annotation) 是一种特殊的修饰符,可以与其他修饰符共同使用。注释由 @
符号、注释类型和包含在括号中的元素值对列表组成。
本节讨论 JSR 250 定义的常用安全注释。共有 5 种(请参阅 参考资料 [6]):
javax.annotation.security.PermitAll
javax.annotation.security.DenyAll
javax.annotation.security.RolesAllowed
javax.annotation.security.DeclareRoles
javax.annotation.security.RunAs
@PermitAll
、@DenyAll
和 @RolesAllowed
注释是为指定 EJB 业务方法权限而定义的。@DeclareRoles
和 @RunAs
是 TYPE 级注释,用于指定与角色相关的元数据。
对于 Web 模块,您仍然需要在 web.xml 应用程序部署描述符中定义一个 <security-constraint>
来添加授权约束,这与 J2EE 1.4 相类似。在 Java EE 5 环境中,与权限相关的注释仅为 EJB 模块定义。下表总结了这些注释的基本用法。有关详细信息,请参阅 JSR 250 规范(参考资料 [5])。
注释
目标
EJB 或其超类
Servlet 或 Web 库
描述
类型
方法
@PermitA ll
|
X
|
X
|
X
|
|
指示某 EJB 的某个方法或所有业务方法允许被所有用户访问。
|
@DenyAll
|
|
X
|
X
|
|
指示 EJB 的某个方法不允许被任何用户访问。
|
@RolesAllowed
|
X
|
X
|
X
|
|
指示 EJB 的某个方法或所有业务方法允许被角色列表中的用户访问。
|
@DeclareRoles
|
X
|
|
X
|
X
|
定义安全检查的角色,供 EJBContext.isCallerInRole、HttpServletRequest.isUserInRole 和 WebServiceContext.isUserInRole 使用。
|
@RunAs
|
X
|
|
X(不适用于非 EJB 超类)
|
X(仅适用于 Servlet)
|
指定某个组件的 run-as 角色。
|
注意:
- 对于
@PermitAll
、@DenyAll
和 @RolesAllowed
注释,类级别的注释适用于类,方法级的注释适用于方法。方法级注释覆盖类级注释行为。
示例:请参考以下代码:
<!-- BEGIN VCD7 CODE SAMPLE COMPONENT -->
@Stateless @RolesAllowed("javaee") public class HelloEJB implements Hello { @PermitAll public String hello(String msg) { return "Hello, " + msg; }
public String bye(String msg) { return "Bye, " + msg; } }
|
<!-- END VCD7 CODE SAMPLE COMPONENT -->在该示例中,hello()
方法允许被所有用户访问,bye()
方法允许被 javaee 角色中的用户访问。
-
@DeclareRoles
注释定义了某个组件将要使用的角色列表。在 Java EE 5 环境中,您可以通过 @javax.annotation.Resource
来查找资源,以及通过调用以下 API 来确认用户是否属于某个角色:
组件
检查角色的 API
EJB
|
javax.ejb.EJBContext.isCallerInRole(role)
|
Servlet
|
javax.servlet.http.HttpServletRequest.isUserInRole(role)
|
Web 服务
|
javax.xml.ws.WebServiceContext.isUserInRole(role)
|
- 尽管
@PermitAll
、@DenyAll
和 @RolesAllowed
注释允许实现大部分的授权决策,但仍需要 @DeclareRoles
注释来帮助实现更为复杂的逻辑。
例如,假设 hello
方法允许被属于角色 A 但同时不属于角色 B 的用户访问,则以下代码片段可以实现此目的:
<!-- BEGIN VCD7 CODE SAMPLE COMPONENT -->
@Stateless @DeclaresRoles({"A", "B"}) public class HelloEJB implements Hello { @Resource private SessionContext sc; public String hello(String msg) { if (sc.isCallerInRole("A") && !sc.isCallerInRole("B")) { ... } else { ... } } }
|
<!-- END VCD7 CODE SAMPLE COMPONENT -->
- 在 Web 模块中,您可以在 Servlet、过滤器和标记库中指定
@DeclareRoles
。JSP 页面不支持注释。
- 嵌入式 Web 服务调用中的 run-as 或调用者的身份标识和客户身份标识之间的关系是没有定义的。无定义则意味着您不能假定 Web 服务调用中的 run-as 和调用者身份标识作为客户标识传递。
- 同一方法中不能同时使用
@DenyAll
、@PermitAll
和 @RolesAllowed
。例如,以下这些用法是无效的:
<!-- BEGIN VCD7 CODE SAMPLE COMPONENT -->
@PermitAll @DenyAll public String hello()
|
<!-- END VCD7 CODE SAMPLE COMPONENT -->有关详细信息,请参阅 JSR 250 规范的 2.11 节。
- 同一方法中不能使用
@RolesAllowed
注释两次以上。
例如,以下用法无效并且会导致编译失败:
<!-- BEGIN VCD7 CODE SAMPLE COMPONENT -->
@RolesAllowed("javaee") @RolesAllowed("j2ee") public String hello()
|
<!-- END VCD7 CODE SAMPLE COMPONENT -->可以在 @RolesAllowed
注释中提供授权角色列表以实现想要的效果,如下所示:
<!-- BEGIN VCD7 CODE SAMPLE COMPONENT -->
@RolesAllowed({"javaee", "j2ee"}) public String hello()
|
<!-- END VCD7 CODE SAMPLE COMPONENT -->
本节讨论安全注释的继承。因为 GlassFish 方法的默认行为是 @PermitAll
,因此为便于阅读,以下讨论将省略该注释。
继承的一般规则如下:
- 对于方法,使用与继承层次结构中选择的方法有关联的注释。
- 对于
@RunAs
注释,只考虑层次结构叶节点中的注释。
- 对于
@DeclareRoles
注释,继承附加在继承层次结构中。
下面这个示例演示了这些注释继承规则:
示例:在 EJB 的如下层次结构中:
<!-- BEGIN IMAGE WITHOUT CAPTION -->
<!-- END IMAGE WITHOUT CAPTION -->
可以使用以下方法权限:
Hello 方法
HelloBaseEJB 方法权限
HelloEJB 方法权限
hello1()
|
允许被 manager 角色中的用户访问
|
允许被所有用户访问
|
hello2()
|
允许被 employee 角色中的用户访问
|
允许被 staff 角色中的用户访问
|
hello3()
|
允许被 employee 角色中的用户访问
|
允许被 staff 角色中的用户访问
|
示例:在 Servlet 的以下层次结构中:
<!-- BEGIN IMAGE WITHOUT CAPTION -->
<!-- END IMAGE WITHOUT CAPTION -->
Servlet
定义的角色
RunAs
HelloBaseServlet
|
employee
|
engineer
|
HelloServlet
|
employee、manager
|
staff
|
HelloServlet2
|
employee
|
|
注意,HelloServlet2
中没有设置 run-as 角色。
使用注释可以简化应用程序的部署描述符。但是在某些场景中,我们仍然需要或者更喜欢使用部署描述符。本节将描述这些场景。
- 对于
@RolesAllowed
的 EJB Web 服务端点,您需要在 sun-ejb-jar.xml 中指定 <login-config>
和 <auth-method>
元素来定义将要使用的身份验证类型。对于用户名密码身份验证,将 <auth-method>
元素设置为 BASIC,如以下示例所示。只有 EJB Web 服务端点需要执行此步骤,EJB 不需要。
<!-- BEGIN VCD7 CODE SAMPLE COMPONENT -->
<sun-ejb-jar> <enterprise-beans> <ejb> <ejb-name>HelloEjb</ejb-name> <webservice-endpoint> <port-component-name>HelloEjb</port-component-name> <login-config> <auth-method>BASIC</auth-method> <realm>default</realm> </login-config> </webservice-endpoint> </ejb> </enterprise-beans> </sun-ejb-jar>
|
<!-- END VCD7 CODE SAMPLE COMPONENT -->
-
@PermitAll
、@RolesAllowed
和 @DenyAll
注释在 servlet 中不受支持。当使用 servlet 时,在 web.xml 部署描述符中指定身份验证和授权方式。以下信息必须在 web.xml 中指定:
-
<security-constraint>/<web-resource-collection>
这些元素指定了受保护 Web 资源的 URL 模式和 HTTP 方法。
-
<security-constraint>/<auth-constraint>
这些元素指定了允许访问受保护 Web 资源的角色列表。
-
<login-config>
该元素指定了将要执行的身份验证类型(例如,<auth-method>
(BASIC 或 FORM))、将要执行身份验证的域 (<realm-name>
),以及(如果是基于表格验证)登录表格和错误页面的位置 (<form-login-config>
)。
-
<security-role>
该元素指定了该 Web 应用程序使用的角色列表。该列表必须包含上面提到的 <auth-constraint>
中指定的角色。
例如,假设您希望保护 index.jsp 页面的 GET 和 POST 方法,只允许 employee 角色访问它们,则需要使用以下 web.xml 配置来实现:
<!-- BEGIN VCD7 CODE SAMPLE COMPONENT -->
... <web-app> <servlet> ... </servlet> <security-constraint> <web-resource-collection> <web-resource-name>MySecureResource</web-resource-name> <url-pattern>/index.jsp</url-pattern> <http-method>GET</http-method> <http-method>POST</http-method> </web-resource-collection> <auth-constraint> <role-name>employee<role-name> </auth-constraint> <user-data-constraint> <transport-guarantee>NONE</transport-guarantee> </user-data-constraint> </security-constraint> <login-config> <auth-method>BASIC</auth-method> <realm-name>default</realm-name> <login-config> <security-role> <role-name>employee</role-name> </security-role> </web-app>
|
<!-- END VCD7 CODE SAMPLE COMPONENT -->
- 对
于只有某个角色才具有访问权限的应用程序来说,您需要在应用程序使用的角色与应用服务器定义的组或主体之间建立映射。为了在应用程序所使用的
employee 角色和应用服务器默认域定义的 engineer 组之间建立映射,您仍然需要在运行时部署描述符
sun-application.xml、sun-ejb-jar.xml 或 sun-web.xml 中指定该安全角色映射。
例如,将以下代码添加到 sun-application.xml 中就可以实现在 engineer 组的所有用户与某个应用程序的 employee 角色之间建立映射。
<!-- BEGIN VCD7 CODE SAMPLE COMPONENT -->
<security-role-mapping> <role-name>employee</employee> <group-name>engineer</group-name> </security-role-mapping>
|
<!-- END VCD7 CODE SAMPLE COMPONENT -->
- 部署描述符覆盖注释行为。
示例:假设有以下 Enterprise JavaBean:
<!-- BEGIN VCD7 CODE SAMPLE COMPONENT -->
@Stateless public class HelloEJB implements Hello { @PermitAll public String hello1(String msg) { return "1: Hello, " + msg; }
@RolesAllowed("javaee") public String hello2(String msg) { return "2: Hello, " + msg; }
@DenyAll public String hello3(String msg) { return "3: Hello, " + msg; } }
|
<!-- END VCD7 CODE SAMPLE COMPONENT -->您可以通过应用程序部署描述符 ejb-jar.xml 来覆盖方法权限:
<!-- BEGIN VCD7 CODE SAMPLE COMPONENT -->
<ejb-jar ...> <enterprise-beans> ... </enterprise-beans> <assembly-descriptor> <security-role>javaee</security-role> <method-permission> <role-name>javaee</role-name> <method> <ejb-name>HelloEJB</ejb-name> <method-intf>Local</method-intf> <method-name>hello1</method-name> </method> </method-permission> <method-permission> <unchecked/> <method> <ejb-name>HelloEJB</ejb-name> <method-intf>Local</method-intf> <method-name>hello3</method-name> </method> </method-permission> <exclude-list> <method> <ejb-name>HelloEJB</ejb-name> <method-intf>Local</method-intf> <method-name>hello2</method-name> </method> </exclude-list> </assembly-descriptor> </ejb-jar>
|
<!-- END VCD7 CODE SAMPLE COMPONENT -->行为如下:
方法
注释
部署描述文件覆盖
hello1()
|
允许被所有用户访问
|
允许被 javaee 角色的用户访问
|
hello2()
|
允许被 javaee 角色的用户访问
|
不允许被任何用户访问
|
hello3()
|
不允许被任何用户访问
|
允许被所有用户访问
|
- 在 GlassFish 中,如果应用程序部署描述文件中没有指定域,则该应用程序将使用默认域。您可以在运行时部署描述符 sun-application.xml 和 sun-ejb-jar.xml 中使用
<realm>
元素或在 web.xml 中使用 <realm-name>
元素来覆盖该设置。
- 如果在 GlassFish 中使用
@RunAs
注
释,则需要将 run-as 角色关联到一个主体,如果只关联了一个主体,则该主体将作为 run-as
主体的默认值;如果关联了多个主体,则需要明确设置 run-as 主体。以下示例演示了如何在 sun-ejb-jar.xml 中设置
run-as 主体:
<!-- BEGIN VCD7 CODE SAMPLE COMPONENT -->
... <ejb> ... <principal> <name>user1</name> </principal> ... </ejb>
|
<!-- END VCD7 CODE SAMPLE COMPONENT -->以下示例演示了如何在 sun-web.xml 中设置 run-as 主体:
<!-- BEGIN VCD7 CODE SAMPLE COMPONENT -->
... <servlet> <servlet-name>myServlet</servlet-name> <principal-name>user1</principal-name> ... </servlet> ...
|
<!-- END VCD7 CODE SAMPLE COMPONENT -->
总而言之,注释可以通过身份验证和授权为 Java EE 5 环境中的应用程序提供安全性。在 Java EE 5 环境中使用身份验证和授权时,通常需要遵循以下几个步骤:
- 创建 Java EE 应用程序。
- 使用 Enterprise JavaBeans 安全注释建立授权约束,或者在 Web 模块的 web.xml 文件中添加安全约束。
- 在相应的部署描述符中添加身份验证需求
<login-config>
。
- 建立域(如果未使用默认域),或者在应用程序部署描述符中指定 run-as 主体。
- 将
<security-role-mapping>
元素添加到运行时部署描述文件中,在应用程序角色和应用服务器组或主体之间建立映射。
- 打包和部署应用程序。
-
How to use Verisign cert in GlassFish and SJSAS 8.x?,Shing Wai Chan 的 Weblog,2005 年 10 月 16 日
-
Enterprise Java Bean over SSL,Shing Wai Chan 的 Weblog,2006 年 4 月 8 日
-
Using JAX-WS-Based Web Services with SSL, in Enterprise Java Technologies Tech Tips for May 30, 2006,Shing Wai Chan,2006 年 5 月 27 日
-
JDBCRealm in GlassFish,Shing Wai Chan 的 Weblog,2006 年 6 月 8 日
-
JSR 250: Common Annotations for the Java Platform
-
Java EE 5 SDK API Specifications: Package
javax.annotation.security
Descripton
感谢 Debbie Carson 和 Rick Palkovic 为本文提出的宝贵建议。
转系:Sun中国技术社区
分享到:
相关推荐
java ee 6 with glassfish 3 java ee 6 with glassfish 3
Java EE 5 Development using GlassFish Application Server
GlassFish 社区奉献的Java EE 应用服务器
He is the author of a Java EE 5 book in France and is also an Expert Member on Java EE 6, EJB 3.1, and JPA 2.0. He is the cofounder of the Paris Java User Group. For more, visit ...
Java EE 5 with Glassfish Application Server 英文版 (pdf)
本书是英文原版的图书 探讨了GlassFish的安装和配置,然后再移动到的Java EE 7的应用程序的开发,涵盖了所有主要的Java EE 7的API。它着重于超越基础开发部署到GlassFish 4应用程序服务器的Java应用程序。本书涵盖了...
解释了什么是应用服务器,以及与JavaEE 5.0规范的关系做了相关的说明,还介绍了Java EE 5.0规范所包含的新增的内容。文中以GlassFish应用服务器为例介绍了什么是参考实现(RI).
GlassFish是Java EE的参考实现。 建筑 先决条件: JDK8 + Maven 3.0.3+ 运行完整版本: mvn install 找到Zip分布: appserver /发行版/glassfish/target/glassfish.zip appserver / distributions / web / ...
Java EE 6 with GlassFish 3 Application Server.rar
Java EE 5 Development using GlassFish Application Server
在Java EE 6的教程:基本概念,四版,是一个任务导向,例如驱动的指南为Java平台企业版6(Java EE 6中)开发企业应用程序。由甲骨文的Java EE 6日团队成员的书面文件,这本书为我们提供了新的平台的深刻理解和中级...
2010 - Beginning Java EE 6 with GlassFish 3 2e (Apress)
Beginning Java EE 6 with GlassFish 3, Second Edition Java Enterprise Edition (Java EE) continues to be one of the leading Java technologies and platforms from Oracle (previously Sun). Beginning Java ...
beginning_java_ee_6_with_glassfish_3_2nd_edition 国外最新J2EE教材
GlassFish 是用于构建 Java EE 5应用服务器的开源开发项目的名称。它基于 Sun Microsystems 提供的 Sun Java System Application Server PE 9 的源代码以及 Oracle 贡献的 TopLink 持久性代码。该项目提供了开发高...
jmx和jmx在glassfish中的应用
Java EE 7官司方例子 也是《Java EE 7 Essentials》(中文翻译《Java EE 7精粹》 2015年2月刚上市)最后一章的讲解例子 最新版 学习Java EE 7新手必看 很有帮助 本人运行环境: NetBeans8 0 2+GlassFish4 1 或者...
介绍glassfish以及JAVA EE 5的关系,包含了glassfish的安装配置等信息