第 2 章 EJB 知识与运行环境设置( 4 )
(上接第 2 章的第 3 部分)
30. 定时服务( Timer Service )
1) 定时服务用于在一段特定时间后执行某段程序。定时服务可以用在无状态会话 Bean 和消息驱动 Bean 上。
2) 当无状态会话 Bean 或消息驱动 Bean 的定时器启动时,容器会从实例池中选择 Bean 的一个实例,然后调用其 @timeout 回调方法。
3) 可以使用 @Resource TimerService ts; 来注入定时服务,或者使用容器对象 SessionContext 创建定时器。
4) 关于 TimerService 接口
l 主要用到 createTimer() 方法,用于创建定时器;
l Timer createTimer (Date initialExpiration, long intervalDuration, Serializable info)
Date initialExpiration :定时器启动时间,如果晚于当前时间,则会立即启动;
long intervalDuration :距触发下次定时事件的间隔时间,单位毫秒;
Serializable info :传给定时器的参数,该参数必须实现 Serializable 接口。
5) 在定时事件被触发时,标注为 @Timeout 的回调方法会被调用。该方法,必须是 void ,且接受一个 javax.ejb.Timer 类型的参数。
6) 关于 Timer 接口
l cancel() : void ,用于取消当前 Timer 定时器以及其相关的触发;
l getInfo() :返回 Serializable ,获得在创建 Timer 时( TimerService 的 createTimer 方法),传入的信息。
31. 安全服务
1) Java 验证与授权服务( JAAS )可以用来管理应用程序安全。两个特性:
l 验证( Authentication )
l 授权( Authorization )
2) 使用流程:
3) 定义安全域
在 JBoss 的安装目录下的 /server/default/conf/login-config.xml 中,包含有几种预设的安全域( Security-Domain )。也可以在这里自定义安全域。
JBoss 的默认安全域是“ other ”:
< application-policy name = "other" >
< authentication >
< login-module code = "org.jboss.security.auth.spi.UsersRolesLoginModule" flag = "required" />
</ authentication >
</ application-policy >
4) 指定安全域:即告诉容器从何处寻找用户密码和用户角色列表三种方法。
l 在 jboss.xml 中定义, jboss.xml 必须置于 jar 文件的 META-INF 目录下。
<? xml version = "1.0" encoding = "UTF-8" ?>
< jboss >
< security-domain > other </ security-domain >
< unauthenticated-principal >
AnonymousUser
</ unauthenticated-principal >
</ jboss >
other 安全域是在 EJB 的 classpath 下寻找 users.properties 和 roles.properties 。
l 在 jboss-web 中定义,即 Web 应用与 EJB 使用同一个安全域,如果 Web 验证通过,将使用 Web 角色访问 EJB 。 jboss-web.xml 应置于 WEB-INF 目录下。
<? xml version = "1.0" encoding = "UTF-8" ?>
<! DOCTYPE jboss-web PUBLIC "-//JBoss//DTD Web Application 2.3V2//EN" "http://www.jboss.org/j2ee/dtd/jboss-web_3_2.dtd" >
< jboss-web >
< security-domain > java:/jaas/other </ security-domain >
</ jboss-web >
应将 users.properties 和 roles.properties 置于 WEB-INF/classes 目录下,否则 Web 的 ClassLoader 找不到文件后会交给 EJB 的 ClassLoader 去寻找。
在 web.xml 中配置权限设置:
<? xml version = "1.0" encoding = "UTF-8" ?>
< web-app xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xmlns = "http://java.sun.com/xml/ns/javaee" xmlns:web = "http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation = "http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id = "WebApp_ID" version = "2.5" >
< display-name > EJBClient02 </ display-name >
< error-page >
< error-code > 403 </ error-code >
< location > /notAuthenticated.html </ location >
</ error-page >
< security-constraint >
< web-resource-collection >
< web-resource-name > Protected Pages </ web-resource-name >
< url-pattern > /member/* </ url-pattern >
< http-method > POST </ http-method >
< http-method > GET </ http-method >
</ web-resource-collection >
< auth-constraint >
< role-name > DormitoryMember </ role-name >
</ auth-constraint >
< user-data-constraint >
< transport-guarantee > NONE </ transport-guarantee >
</ user-data-constraint >
</ security-constraint >
< security-constraint >
< web-resource-collection >
< web-resource-name > Protected Pages </ web-resource-name >
< url-pattern > /admin/* </ url-pattern >
< http-method > POST </ http-method >
< http-method > GET </ http-method >
</ web-resource-collection >
< auth-constraint >
< role-name > DormitoryAdmin </ role-name >
</ auth-constraint >
< user-data-constraint >
< transport-guarantee > NONE </ transport-guarantee >
</ user-data-constraint >
</ security-constraint >
< security-role >
< role-name > DormitoryAdmin </ role-name >
</ security-role >
< security-role >
< role-name > DormitoryMember </ role-name >
</ security-role >
< login-config >
< auth-method > FORM </ auth-method >
< form-login-config >
< form-login-page > /login.html </ form-login-page >
< form-error-page > /loginFailed.html </ form-error-page >
</ form-login-config >
</ login-config >
</ web-app >
l 使用 @SecurityDomain 注释在 EJB 类中直接指定安全域,不过这种方式是硬编码,不利于移植,因此不建议使用。
5) 为业务方法定义访问角色
l @RolesAllowed :指定允许访问该业务方法的角色列表;
l @PermitAll :指定该业务方法允许任何角色访问。
6) 开发客户端
l 当使用 jboss.xml 指定安全域时, JBoss 是通过 JNDI API 来完成身份验证,因此需要把用户名和密码分别设置在 Context.SECURITY_PRINCIPAL 和 Context.SECURITY_CREDENTIALS 上(通过 Properties ),传递给 InitialContext 。
l 当使用 jboss.xml 时, Web 容器会根据安全域设置,自己完成身份验证。
l 注意在 JSP 中 logout 时,应该把 request.getSession 强制转换为 HttpSession 后在执行 invalidate() ,同时也要调用 SecurityAssociation.clear() 方法。
7) 自定义安全域
l login-config.xml 中:
< application-policy name = "room605" >
< authentication >
< login-module code = "org.jboss.security.auth.spi.DatabaseServerLoginModule" flag = "required" >
< module-option name = "dsJndiName" > java:/DefaultMySqlDS
</ module-option >
< module-option name = "principalsQuery" >
select password from sys_user where username=?
</ module-option >
< module-option name = "rolesQuery" >
select rolename, 'Roles' from sys_userrole where username=?
</ module-option >
</ login-module >
</ authentication >
</ application-policy >
上面使用了 JBoss 数据库登录模块( org.jboss.security.auth.spi.DatabaseServerLoginModule ):
dsJndiName 属性:指定数据源 JNDI 名称;
principalsQuery 属性:指定如何通过给定用户名获取密码;
rolesQuery 属性:指定如何通过给定用户名获取角色列表(‘ Roles ’常量字段不能去掉);
l 在 jboss.xml 中:
<? xml version = "1.0" encoding = "UTF-8" ?>
< jboss >
< security-domain > room605 </ security-domain >
< unauthenticated-principal > AnonymousUser </ unauthenticated-principal >
</ jboss >
l 或在 jboss-web.xml 中:
<? xml version = "1.0" encoding = "UTF-8" ?>
<! DOCTYPE jboss-web PUBLIC "-//JBoss//DTD Web Application 2.3V2//EN" "http://www.jboss.org/j2ee/dtd/jboss-web_3_2.dtd" >
< jboss-web >
< security-domain > java:/jaas/room605 </ security-domain >
</ jboss-web >