2017-07-27 41 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