我正在使用Java EE 6和Shiro for REST后端开发一个Web应用程序,这可以通过基于Angular的前端访问。
在shiro中禁用了会话创建(shiro.ini中的noSessionCreation),我根据他/她提供登录凭据后收到的令牌,对每个请求进行身份验证。
在自定义验证过滤器中,我正在调用
SecurityUtils.getSubject().login(bearerToken);
调用自定义身份验证领域并验证凭据。
我有一个Dao,我想使用存储在Shiro Subject的主要信息中的用户ID。
final UserInfo userInfo = (UserInfo) SecurityUtils.getSubject().getPrincipal();
final Long currentUserId = userInfo.getId();
Dao本身是一个@Singleton EJB
@Singleton
public class TaskDao {
...
public List<Task> filterActiveTasks() {
}
}
在这种情况下,我想过滤属于访问该服务的用户的活动任务。
同时我的问题和疑虑:
这个线程安全吗?在并发使用时,受试者可能会混淆不清吗?
如果是这样,怎么可以避免?
修改
我关注的不仅仅是activeTasks,还适用于我想使用SecurityUtils.getSubject()静态方法的任何@Singleton注释类。
public List<SomeData> getSomeDataRelatedToCurrentlyLoggedInUser() {
// Since the following is a static call in a singleton, how can I be sure
// that when 10 users are calling this at the same time, each call will get
// the appropriate UserInfo that was "logged-in" at the AuthenticatingFilter level
final UserInfo userInfo = (UserInfo) SecurityUtils.getSubject().getPrincipal();
Long currentUserId = userInfo.getId();
return em.createNamedQuery("select s from SomeData s where s.userId = :userId").
setParameter("userId", currentUserId).
getResultList();
}
登录部分在自定义AuthenticatingFilter中完成,为每个用户创建-AFAIK.
所以问题仍然存在:对SecurityUtils.getSubject()的调用是否会返回正确的用户,还是可以将它们混合起来?如何在执行登录机制时检索用户绑定的单例中的threadcontext?
答案 0 :(得分:0)
您可以在单例ejb中简单地引入ThreadLocal变量。
这样,您只需将与当前线程/用户相关的内容放入变量中。例如:
@Singleton
public class TaskDao {
private static ThreadLocal<Set<ActiveTasks>> tasksThreadLocal = new ThreadLocal<>(){
@Override
protected Set<ActiveTasks> initialValue() {
return new HashSet<>();
}
};
filterActiveTasks() {
Set<ActiveTasks> tasks = tasksThreadLocal.get();
//work with the Set
}
}
这样,集合对每个线程都是本地的,不会出现多线程问题。
对于SecurityUtils.getSubject(),此方法在内部使用相同的机制,因此它始终只返回当前线程上的用户,从而返回登录到当前请求的用户。它使用ThreadContext类,它使用ThreadLocal存储当前用户/登录会话。
如果你想以某种方式访问该对象(在大多数情况下,你没有)它有一堆静态公共方法,你可以直接调用设置/获取像主题或安全管理器的东西当前主题。