Jakarta ee Jersey:区分会话超时和缺少授权

Jakarta ee Jersey:区分会话超时和缺少授权,jakarta-ee,exception,tomcat,jersey,jax-rs,Jakarta Ee,Exception,Tomcat,Jersey,Jax Rs,我使用的Jersey(1.18.1)启用了RolesAllowedResourceFilterFactory。 假设我有以下资源: @RolesAllowed("SuperUser") @Path("/resource") class Resource{ //some code here } 当会话超时时,在访问此资源时,服务器抛出一个WebApplicationException,没有任何消息,但如果没有必要角色的用户试图访问给定资源,它也会这样做。因此:如何区分会话超时和缺少必要角色?

我使用的Jersey(1.18.1)启用了
RolesAllowedResourceFilterFactory
。 假设我有以下资源:

@RolesAllowed("SuperUser")
@Path("/resource")
class Resource{
  //some code here
}
当会话超时时,在访问此资源时,服务器抛出一个
WebApplicationException
,没有任何消息,但如果没有必要角色的用户试图访问给定资源,它也会这样做。因此:如何区分会话超时和缺少必要角色?


我之所以需要这样做,是因为我想向前端发送一条适当的消息(从一个
ExceptionMapper
)并在那里采取适当的措施。

我认为没有一种内置方法可以做到这一点,因为容器需要记住过期的sessionID及其相关用户。据我所知,容器只会在会话超时时删除此信息。 但你可以试着自己做:

实现并将过期的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中,您现在可以检查JSSessionID 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();
    } 

}
@Provider
公共类ExMapper实现ExceptionMapper{
@注入
私有会话缓存;
@上下文
私有HttpServletRequest;
@凌驾
公众回应(例外情况除外){
for(Cookie:request.getCookies()){
if(“JSESSIONID.equals(cookie.getName())){
字符串sessionId=cookie.getValue().substring(0,cookie.getValue().lastIndexOf('.');//忽略.hostname
if(cache.contains(sessionId)){
返回Response.serverError().entity(“您的会话超时”).build();
}
}
}
返回Response.serverError().build();
} 
}

您应该考虑不时清理缓存。

我通过将
SecurityContext
注入
exceptionapper
并检查用户是否分配了任何角色,解决了这个问题。如果有,并且
webAppException.getResponse().getStatus()
状态代码等于
禁止(403)
,则异常的原因是缺乏授权(用户没有必要的角色)。如果用户没有任何分配的角色,并且响应的状态代码再次为403,则表示会话已过期,否则会导致异常

这种方法有一个很大的缺点——它要求所有用户至少分配一个角色,否则它将无法工作