我使用Jersey(1.18.1)启用了RolesAllowedResourceFilterFactory
。
假设我有以下资源:
@RolesAllowed("SuperUser")
@Path("/resource")
class Resource{
//some code here
}
在会话超时时访问此资源时,服务器会抛出WebApplicationException
而没有任何消息,但如果没有必要角色的用户尝试访问给定资源,它也会执行此操作。那么:如何区分会话超时和缺少必要的角色?
我需要这样做,因为我想发送一个适当的消息(从ExceptionMapper
)到前端并在那里采取适当的措施。
答案 0 :(得分:0)
我认为没有构建方法可以实现此目的,因为容器需要记住过期的sessionId及其关联用户。据我所知,容器只会在会话超时时删除此信息。 但你可以尝试自己做这件事:
实现HttpSessionListener并将过期的SessionID存储在某种缓存中。您很可能只想向授权用户显示此“会话过期”消息,但也可能为非授权用户创建HTTP会话。因此,您需要检查用户是否已获得授权。由于您无法访问SessionListener中的UserPrincipal,因此您需要自行在会话中存储一些信息。
@WebListener
public class HttpSessionChecker implements HttpSessionListener {
@Inject
private SessionIdCache cache;
public void sessionCreated(HttpSessionEvent event) {}
public void sessionDestroyed(HttpSessionEvent event) {
if (event.getSession().getAttribute("someAuthInformation") != null) { // whatever you've stored
cache.put(event.getSession().getId(), new Date());
}
}
}
在您的ExceptionMapper中,您现在可以检查JSESSIONID-Cookie是否是请求标头的一部分,以及是否在缓存中找到了传递的sessionID。
@Provider
public class ExMapper implements ExceptionMapper<Exception> {
@Inject
private SessionIdCache cache;
@Context
private HttpServletRequest request;
@Override
public Response toResponse(Exception ex) {
for (Cookie cookie : request.getCookies()) {
if ("JSESSIONID".equals(cookie.getName())) {
String sessionId = cookie.getValue().substring(0, cookie.getValue().lastIndexOf('.')); // ignore .hostname
if (cache.contains(sessionId)) {
return Response.serverError().entity("Your session timed out").build();
}
}
}
return Response.serverError().build();
}
}
您应该考虑不时清理缓存。
答案 1 :(得分:0)
我通过将SecurityContext
注入ExceptionMapper
并检查用户是否分配了任何角色来解决问题。如果它已经且webAppException.getResponse().getStatus()
状态代码等于FORBIDDEN(403)
,那么异常的原因是缺乏授权(用户没有必要的角色)。如果用户没有任何已分配的角色,并且响应的状态代码再次为403 - 则表示会话已过期,否则其他原因是异常的原因。
这种方法有一个很大的缺点 - 它要求所有用户至少拥有一个指定的角色,否则它将无法工作;