2017-07-27 66 views
0

我有一个Spring 4 + Jersey 2 Web应用程序,它使用JWT进行身份验证。ContainerRequestFilter随机给出null

我使用ContainerRequestFilter拦截每个呼叫,并检查是否该请求具有正确Authorization令牌:

import java.util.Map; 

import javax.ws.rs.container.ContainerRequestContext; 
import javax.ws.rs.container.ContainerRequestFilter; 
import javax.ws.rs.ext.Provider; 

import org.apache.logging.log4j.LogManager; 
import org.apache.logging.log4j.Logger; 

import com.auth0.jwt.JWT; 
import com.auth0.jwt.interfaces.Claim; 
import com.auth0.jwt.interfaces.DecodedJWT; 

import my.beans.User; 

@Provider 
public class JWTFilter implements ContainerRequestFilter { 
    private static final Logger LOG = LogManager.getLogger(JWTFilter.class); 


    @Override 
    public void filter(ContainerRequestContext context) { 
     LOG.debug("JWT Filter"); 
     String authorization = context.getHeaderString("Authorization"); 
     if(authorization != null) { 
      String jwtToken = authorization.replaceAll(".*Bearer\\s+", ""); 
      DecodedJWT jwt = JWT.decode(jwtToken); 
      Map<String, Claim> claims = jwt.getClaims(); 
      String userid = claims.get("userid").asString(); 

      if(userid != null) { 
       User user = loadUser(userid); 

       // save user to request, so that it gets 
       context.setProperty("loggedUser", user); 

       LOG.debug("User found: " + user); 
      } 
     } else { 
      LOG.debug("JWT missing"); 
     } 
    } 

    private User loadUser(String userid) { 
     // loads a User object 
    } 
} 

我然后有一个BaseResource类具有getLoggedUser()方法从ContainerRequestContext检索数据:

import javax.ws.rs.container.ContainerRequestContext; 
import javax.ws.rs.core.Context; 

import org.apache.logging.log4j.LogManager; 
import org.apache.logging.log4j.Logger; 

import my.beans.User; 

public class BaseResource { 

    private static final Logger LOG = LogManager.getLogger(BaseResource.class); 

    @Context 
    private ContainerRequestContext context; 

    public User getLoggedUser() { 
     User u = (User) context.getProperty("loggedUser"); 
     LOG.debug("getLoggedUser(): " + u); 
     return u; 
    } 

} 

BaseResource类被所有Jersey资源扩展。

这是我所拥有的资源之一:

import javax.ws.rs.GET; 
import javax.ws.rs.Path; 
import javax.ws.rs.Produces; 
import javax.ws.rs.core.Response; 

import org.springframework.http.MediaType; 
import org.springframework.stereotype.Component; 

import my.beans.User; 

@Component 
@Path("/test") 
public class TestResource extends BaseResource { 

    @GET 
    @Produces(MediaType.APPLICATION_JSON_VALUE) 
    @Path("/") 
    public Response test() { 
     User u = getLoggedUser(); 

     return Response.ok().build(); 
    } 
} 

如果我尝试执行这个资源,我得到这个日志:

DEBUG: JWT Filter 
DEBUG: User found: [email protected] 
DEBUG: getLoggedUser(): [email protected] 

看来工作。

如果我开始一次又一次地刷新页面,出现这种情况:

DEBUG: JWT Filter 
DEBUG: User found: [email protected] 
DEBUG: getLoggedUser(): [email protected] 
DEBUG: JWT Filter 
DEBUG: User found: [email protected] 
DEBUG: getLoggedUser(): [email protected] 
DEBUG: JWT Filter 
DEBUG: User found: [email protected] 
DEBUG: getLoggedUser(): null 
DEBUG: JWT Filter 
DEBUG: User found: [email protected] 
DEBUG: getLoggedUser(): [email protected] 

第三次,用户发现JWTFilter类,但说到null控制器内。这很奇怪,因为过滤器把它放在ContainerRequestContext里面,所以这个问题不应该发生。似乎有时ContainerRequestContext无法保存数据,或在到达控制器时丢失数据。

这里发生了什么?为什么在拨打ContainerRequestContest#getProperty时随机获得null对象?我应该这样做吗?

值得一提的是我的过滤器是javax.ws.rs.container.ContainerRequestFilter。我应该改用com.sun.jersey.spi.container.ContainerRequestFilter吗?

回答

0

如果你想从过滤器获取的数据资源,尝试设置HTTP头中的过滤器类,这样就可以在资源类用头PARAM

+0

头可以包含Java对象得到什么? – BackSlash

+0

您可以将json对象转换为字符串并添加到header.Once数据返回到资源使用jackson映射器转换回bean类中的json对象/ map。 –

+0

它不是一个json对象,它是一个java对象。对于我来说,每次将对象传递为标题看起来都是不必要的开销。 'ContainerRequestContext'应该在这里工作,我不应该使用头文件。 – BackSlash