Jakarta ee Jersey:区分会话超时和缺少授权
我使用的Jersey(1.18.1)启用了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,没有任何消息,但如果没有必要角色的用户试图访问给定资源,它也会这样做。因此:如何区分会话超时和缺少必要角色?
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,则表示会话已过期,否则会导致异常
这种方法有一个很大的缺点——它要求所有用户至少分配一个角色,否则它将无法工作