差異處

這裏顯示兩個版本的差異處。

連向這個比對檢視

Both sides previous revision 前次修改
下次修改
前次修改
java:web:restapi:x-http-method-override_filter [2016/02/26 21:52]
tony [Trace]
java:web:restapi:x-http-method-override_filter [2023/06/25 09:48] (目前版本)
行 1: 行 1:
 +{{tag>​java spring rest}}
 ====== Incorrect response(401) when using X-HTTP-Method-Override ====== ====== Incorrect response(401) when using X-HTTP-Method-Override ======
 ===== Problem ===== ===== Problem =====
行 12: 行 13:
 Sprint Security提供了DigestAuthentationFilter負責處理Digest認證。在使用者發出第一次請求後,Spring Security在察覺未經過驗證的情況下,會透過AuthenticationEntryPoint送出請求認證資訊。而為了在認證失敗時,能夠輸出xml或json格式的錯誤訊息(可參考上方),我們extend了DigestAuthenticationEntryPoint:​ Sprint Security提供了DigestAuthentationFilter負責處理Digest認證。在使用者發出第一次請求後,Spring Security在察覺未經過驗證的情況下,會透過AuthenticationEntryPoint送出請求認證資訊。而為了在認證失敗時,能夠輸出xml或json格式的錯誤訊息(可參考上方),我們extend了DigestAuthenticationEntryPoint:​
 <code java> <code java>
-public class JsonDigestAuthenticationEntryPoint ​extends DigestAuthenticationEntryPoint {+public class CustomziedDigestAuthenticationEntryPoint ​extends DigestAuthenticationEntryPoint {
  
  private static final Log logger = LogFactory.getLog(JsonDigestAuthenticationEntryPoint.class);​  private static final Log logger = LogFactory.getLog(JsonDigestAuthenticationEntryPoint.class);​
行 41: 行 42:
 } }
 </​code>​ </​code>​
-在這裡的authException,就是我們所看到的Incorrect Response。於上我就往上trace,發現DigestAuthentationFilter會透過request method去算digest值。+在這裡的authException,就是我們所看到的Incorrect Response。於上我就往上trace,發現DigestAuthentationFilter會透過request method去算reponse值。 
 +===== Root Cause ===== 
 +仔細看一下[[https://​en.wikipedia.org/​wiki/​Digest_access_authentication|Digest認證流程]],其中吸引我目光的是:​ 
 +<​code>​ 
 +HA1=MD5(username:​realm:​password) 
 +HA2=MD5(method:​digestURI) 
 +response=MD5(HA1:​nonce:​HA2) 
 +</​code>​ 
 +接著套入我們的情境:​\\ 
 +{{:​java:​web:​restapi:​rest_digest_filter_with_override_method_bug.png?​600|}}\\ 
 +  - Client收到Server認證請求。 
 +  - Client對Server發送認證內容,其中包含response值。 
 +  - Server的RestHeaderFilter首先處理X-HTTP-Method-Override請求,將Request method由Post改為Delete。 
 +  - Server的DigestAuthenticationFilter發現response不相同。 
 +  - Server回應錯誤訊息給Client。 
 +這問題就在於:​ Client使用POST當method去計算HA2;而Server由於經過Request method的取代,會用DELETE去計算HA2。 
 +===== Solution ===== 
 +那調整一下順序不就好了嗎?​ 的確,在我將RestHeaderFilter設定在Security相關Filter後,請求就可以正常處理了。但其實我們的RestHeaderFilter,還身兼將Rest API版本資訊塞到Header的責任。因此最後調整的順序為:​ 
 +  - RestHeaderFilter 
 +  - SpringSecurityFilter 
 +  - HttpMethodOverrideFilter 
 +<code java> 
 +public class HttpMethodOverrideFilter extends OncePerRequestFilter implements Filter { 
 + private static final Logger logger = LoggerFactory.getLogger(HttpMethodOverrideFilter.class);​ 
 + protected static final String X_HTTP_METHOD_OVERRIDE_HEADER = "​X-HTTP-Method-Override";​ 
 +  
 + @Override 
 + protected void doFilterInternal(HttpServletRequest aRequest, HttpServletResponse aResponse, FilterChain aFilterChain) 
 + throws ServletException,​ IOException { 
 +  
 + String methodOverrideValue = aRequest.getHeader(X_HTTP_METHOD_OVERRIDE_HEADER);​ 
 + if (methodOverrideValue != null && !methodOverrideValue.isEmpty()) { 
 + String overrideMethod = methodOverrideValue.toUpperCase(Locale.ENGLISH);​  
 + aRequest = new HttpMethodRequestWrapper(aRequest,​ overrideMethod);​ 
 +
 + aFilterChain.doFilter(aRequest,​ aResponse);​ 
 +
 + 
 + private static class HttpMethodRequestWrapper extends HttpServletRequestWrapper { 
 + private final String method; 
 + 
 + public HttpMethodRequestWrapper(HttpServletRequest request, String method) { 
 + super(request);​ 
 + this.method = method; 
 +
 + 
 + @Override 
 + public String getMethod() { 
 + return this.method;​ 
 +
 +
 +
 +</​code>​ 
 +===== Note ===== 
 +如果有使用PostMan,可以仔細看看選擇不同的HTTP method,是否會產生不同的digest response。 
 +=====    ===== 
 +---- 
 +\\ 
 +~~DISQUS~~