CROS實現跨域時授權問題(401錯誤)的解決

flak9724 8年前發布 | 34K 次閱讀 Tomcat 前端技術 Apache HTTP Server

如果我們訪問的資源是不需要授權的,也就是在HTTP請求頭中不包含 authentication 頭那么以上做法就足夠了。但是如果該資源是需要權限驗證的,那么這個時候跨域請求的預檢測 option 請求,由于不會攜帶身份信息而被拒絕 。瀏覽器會報出401錯誤。

前幾天的文章 Spring通過CROS協議解決跨域問題 中提到了如何解決跨域問題的基本思路,解決了跨域請求時瀏覽器403錯誤。

Response to preflight request doesn't pass access control check:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'null' is therefore not allowed access. 
The response had HTTP status code 403

401錯誤信息如下:

Failed to load resource:
the server responded with a status of 401 (Unauthorized)
XMLHttpRequest cannot load http://localhost/api/test.
Response for preflight has invalid HTTP status code 401

既然知道了問題的原因,答案也就很容易得出: 對需要進行跨域請求的資源(api),當服務端檢測到是 OPTONS 請求時候統統放行,給出HTTP.OK(200)的狀態和必要的響應頭,哪怕它是不帶身份信息的 。

這個問題既可以通過編寫對應的后端代碼實現,也可以通過設置服務器配置文件實現。也就是如何設置響應頭和返回200狀態碼的辦法了。

Spring+Shrio的解決方案

shiro中可以在自己實現的身份驗證filter中加入以下代碼:

@Override
  protected boolean preHandle(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
      HttpServletRequest request = (HttpServletRequest) servletRequest;
      HttpServletResponse response = (HttpServletResponse) servletResponse;
      if(request.getMethod().equals(RequestMethod.OPTIONS.name()))
      {
          response.setStatus(HttpStatus.OK.value());
          return false;
      }
      return super.preHandle(request, response);
  }

shiro中AccessControlFilter提供了訪問控制的基礎功能;比如是否允許訪問/當訪問拒絕時如何處理等,也是我們一般自定義權限驗證時候的一個父類,我們通過重寫他的 onPreHandle 方法判斷是否是 option 請求,如果是則設置相應狀態,(響應頭已經在之前文章中通過filter配置過了)返回false表示該攔截器實例已經處理了,將直接返回即可。

Tomcat配置

需要修改tomcat的全局web.xml文件在 CATALINA_HOME/conf 下,加入以下配置。

<filter>
       <filter-name>CorsFilter</filter-name>
       <filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
     </filter>
     <filter-mapping>
       <filter-name>CorsFilter</filter-name>
       <url-pattern>/*</url-pattern>
     </filter-mapping>

Nginx配置

add_header 'Access-Control-Allow-Methods' 'GET,OPTIONS,PUT,DELETE' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Allow-Origin' '$http_origin' always;
add_header 'Access-Control-Allow-Headers' 'Authorization,DNT,User-Agent,Keep-Alive,Content-Type,accept,origin,X-Requested-With' always;

if ($request_method = OPTIONS ) {
    return 200;
}

Apache配置

Header always set Access-Control-Allow-Origin "http://waffle"
Header always set Access-Control-Allow-Methods "POST, GET, OPTIONS"
Header always set Access-Control-Allow-Credentials "true"
Header always set Access-Control-Allow-Headers "Authorization,DNT,User-Agent,Keep-Alive,Content-Type,accept,origin,X-Requested-With"

RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule ^(.*)$ $1 [R=200,L]

js請求示例

請求時候需要加上 Authorization 和 Content-Type 頭。

$http({
  method: 'POST',
  url: scope.webdav.url,
  withCredentials: true,
  headers: {
    Authorization: 'Basic ' + btoa(user + ':' + password),
    'Content-Type': 'application/vnd.google-earth.kml+xml; charset=utf-8'
  },
  data: getKml()
})

參考文章: http://www.jujens.eu/posts/en/2015/Jun/27/webdav-options/

 

來自: http://blog.kbiao.me/2016/05/21/CROS實現跨域時授權問題(401錯誤)的解決/

 

 本文由用戶 flak9724 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!