TomEE中JSF自定义表单登录后EJB的@RolesAllowed注解不生效如何解决
TomEE 8.x 自定义JSF表单登录适配EJB @RolesAllowed 解决方案
核心问题原因
TomEE的Web层(Servlet/JSF)和EJB层(OpenEJB)安全上下文默认隔离,Java EE Security API定义的自定义表单认证身份仅默认同步到Web层,未传递到OpenEJB的安全校验链路,导致EJB的注解校验拿到的身份/角色信息缺失。
修复步骤
统一角色声明配置
首先保证Web层和EJB层的角色定义一致,避免映射不匹配:
- 在EJB实现类上添加
@DeclareRoles("testRole")注解,或在EJB模块META-INF/ejb-jar.xml中全局声明角色:<ejb-jar version="3.2" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/ejb-jar_3_2.xsd"> <assembly-descriptor> <security-role> <role-name>testRole</role-name> </security-role> </assembly-descriptor> </ejb-jar> - 在Web模块
WEB-INF/web.xml中同步声明相同的角色:<web-app ...> <security-role> <role-name>testRole</role-name> </security-role> </web-app>
- 在EJB实现类上添加
开启安全上下文传播配置
修改TomEE
conf目录下的system.properties,添加以下2项配置:# 启用JACC安全上下文同步,打通Web层和EJB层的身份传递 tomee.security.jacc=true # 允许OpenEJB委托使用Web层的认证结果,不单独做身份校验 openejb.security.delegation=true你之前配置的
JAASRealm无需修改,保持现有配置即可。校验身份存储返回的角色类型
如果你使用了自定义
@IdentityStore实现身份校验,需要保证返回的角色集合的类型为org.apache.openejb.core.security.jaas.GroupPrincipal,和JAASRealm中配置的roleClassNames一致,否则OpenEJB无法识别角色信息。
排查OpenEJB内部校验逻辑方法
- 开启安全调试日志,修改TomEE
conf/logging.properties,添加以下配置:
重启服务后触发报错,日志会打印出EJB调用时的Principal名称、携带的角色列表、以及角色校验失败的具体原因,可直接定位是身份未传递、角色列表为空还是角色名不匹配。org.apache.openejb.core.security.level = FINEST org.apache.openejb.core.stateless.level = FINE - 在调用EJB方法前,分别打印
SecurityContext.getCallerPrincipal().getName()和EJBContext.getCallerPrincipal().getName(),若EJB层拿到的Principal为anonymous,说明安全上下文传播配置未生效,可重新检查system.properties的配置是否正确加载。
注:如果调用的是
@Asynchronous异步EJB方法,需额外添加openejb.security.propagate-context=true到system.properties中,保证异步线程也能继承安全上下文。
内容的提问来源于stack exchange,提问作者Marcus
相关产品推荐
相关产品推荐

