【问题标题】:EJB3.1 TimerService @Timeout current principalEJB3.1 TimerService @Timeout 当前主体
【发布时间】:2025-12-13 21:55:02
【问题描述】:

我有一个关于身份验证和 TimerService @Timeout 注释的问题:

在我们的应用程序中,用户可以安排任务以给定的时间间隔执行,他们从任务列表中进行选择,每个任务都与应用程序中的特定 EJB 相关联。当用户按下保存按钮时,一个新的计时器将添加到 Timer 服务中,当调用 @Timeout 方法时,使用 @Timeout 方法调用用户指定的 EJB 上的一个方法

Timerservice 调用超时方法时,当前主体为“ANONYMOUS”。如果您需要从 timout 方法中调用任何受保护的 EJB,这将是有问题的。是否可以将当前的主体和角色更改为与创建计时器的用户相同的主体和角色?

@Singleton
@LocalBean
public class TestEJB 
{

    @Resource
    SessionContext context;
    @Resource
    TimerService timerService;

    @Timeout
    public void execute(Timer timer) throws Exception {
        //Get the current username
        System.out.println(context.getCallerPrincipal().getName());
    }

    public void createScheduledTimer(ScheduleExpression e,String timerId) throws IllegalArgumentException, IllegalStateException, EJBException {
        TimerConfig tc = new TimerConfig();
        tc.setInfo(timerId);
        tc.setPersistent(true);
        timerService.createCalendarTimer(e, tc);
    }

}

【问题讨论】:

    标签: java authentication timer ejb-3.1


    【解决方案1】:

    我们在 Glassfish 中做到了这一点。在我们的例子中,我们有一个通用的 Timer bean,它可以运行多个任务中的任何一个,而不是像您正在执行的每个任务一个 bean,但概念是相同的。

    我们最终做的是在提交任务时记录用户,然后我们利用 Glassfish 的特定 ProgramaticLogin 工具在计时器启动时让用户重新登录。这样,整个 EJB 安全上下文就会为用户和任务正确设置。

    【讨论】:

    • @Timeout public void execute(Timer timer){ProgrammaticLogin programmaticLogin = new ProgrammaticLogin(); programmaticLogin.login(用户名,密码);
    • 嗨,谢谢一百万,这正是我想要的,我们也在 glassfish 上运行我们的应用程序,我找不到很多关于程序登录的示例,你的实现看起来是否类似于以下: ProgrammaticLogin programmaticLogin = new ProgrammaticLogin(); programmaticLogin.login(用户名,密码);
    • 是的,这就是我们使用的。我应该注意,我们在实现中使用了自定义领域(通常 Glassfish 只带有一个文件、jdbc 和一个 LDAP 领域)。我们做的另一件事是传递签名令牌而不是 Realm 可以检测到的密码,以便知道“它来自我们”,这样我们就不需要以纯文本形式获取用户的实际密码。
    【解决方案2】:

    【讨论】:

    • 您好,感谢您的回答,RunAs 注释确实解决了部分问题,但是,是否可以作为特定用户从 timout 方法中调用 EJB?因此,如果调用的 EJB 调用 context.getCallerPrincipal() 它将返回用户名?
    【解决方案3】:

    由于您使用的是 3.1 有状态会话 Bean,因此计时器支持。尝试使用@Stateful 而不是@Singleton 来注释您的bean。然后尝试在您的 createScheduledTimer 方法中获取用户名。将其存储为私有字段,然后在@Timeout 方法中对其进行访问。

    【讨论】:

    • SFSB 不支持计时器。您也许可以持有对 SFSB 的引用,但这取决于计时器是否会在 SFSB 超时之前触发。
    • 我以为在 3.1 中添加了支持?来自 JSR:EJB 计时器服务增强功能以​​支持类似 cron 的调度、部署时间计时器创建和有状态会话 bean 定时对象。
    • 在最初的 JSR 318 提案中支持 SFSB,但最终版本(第 18.2 节)说:“可以为无状态会话 bean、单例会话 bean、消息驱动 bean 和2.1 实体bean[94]。不能为有状态会话bean创建定时器[95]。”