文章目錄
1.場景描述
現有微服務a和微服務b,它們均通過一個CAS服務器C實現單點登錄。在微服務a的web頁面需要觸發一段js腳本,這段腳本會通過http的get請求來調用微服務b的相關服務,實現對數據庫的相關操作。
2.問題描述與分析
微服務a對微服務b的跨域請求問題
由於微服務a和微服務b處於不同的域(IP或端口不完全相同),又由於微服務a調用微服務b是通過js腳本,所以瀏覽器會對這樣的跨域請求做限制。發起跨域請求的瀏覽器會在請求報文頭裏的Origin字段裏指明源域(即它本身)的地址。響應的一方需要在應答報文頭的Access-Control-Allow-Origin字段裏指明被允許訪問的域的地址,最後發起跨域請求的瀏覽器會先檢驗這個字段,再決定是否解析及處理該響應報文。所以該場景就需要我們在響應一方的報文頭裏加入Control-Allow-Origin字段及值。
微服務a與CAS服務器C之間的跨域請求問題
當微服務a能夠正常解析並處理微服務b的響應報文的時候,會發現這是一個狀態碼爲302的重定向報文。因爲微服務b在解析到微服務a的請求報文的url的時候,會被微服務b中CAS的過濾器匹配到,做身份驗證的操作,即重定向到CAS服務器做認證。此時,微服務a會發起第二次跨域請求,響應的域是CAS服務器C處在的域。所以這時,我們同樣需要在服務器C上做類似上述在微服務b上的操作。
身份驗證時,對cookie的操作問題
由於CAS做驗證,需要獲取其cookie。所以微服務a發起的跨域請求,必須指明要帶上cookie。
3.問題解決
微服務a發起跨域請求時,帶上cookie,即{‘withCredentials’:true}。這裏用的AngularJS
XMLHttpRequest.withCredentials 屬性是一個Boolean類型,它指示了是否該使用類似cookies,authorization headers(頭部授權)或者TLS客戶端證書這一類資格證書來創建一個跨站點訪問控制(cross-site Access-Control)請求。在同一個站點下使用withCredentials屬性是無效的。
$http.get('http://localhost:9107/xxx,{'withCredentials':true}).success(
function(response){
if(response.success){
alert("成功");
}else{
alert(response.message);
}
}
);
微服務b響應跨域請求時,帶上Access-Control-Allow-Origin
-
微服務b下創建一個過濾器(這個過濾器要在安全框架的過濾器或者CAS的過濾器之前)
web.xml<filter> <filter-name>CORSFilter</filter-name> <filter-class>com.xzt.filter.CORSFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>CORSFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
-
新建java的過濾器類
public class CORSFilter implements Filter{ @Override public void init(FilterConfig filterConfig) throws ServletException { // TODO Auto-generated method stub } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("進入過濾器CORSFilter"); HttpServletResponse resp = (HttpServletResponse)response; HttpServletRequest req = (HttpServletRequest)request; String origin = req.getHeader("Origin"); //這種方式可以靈活的配置Access-Control-Allow-Origin //Access-Control-Allow-Origin的值不要寫*號,因爲對於帶有cookie的跨域請求,瀏覽器不支持這種寬鬆的策略 resp.setHeader("Access-Control-Allow-Origin", origin);//可以訪問的域 resp.setHeader("Access-Control-Allow-Credentials", "true");//如果操作cookie,必須加上這句話 chain.doFilter(request, response); } @Override public void destroy() { // TODO Auto-generated method stub } }
在CAS服務器C上,配置跨域請求
-
在cas的工程路徑下修改web.xml,添加過濾器
cas/WEB-INF/web.xml<filter> <filter-name>CORS</filter-name> <filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class> <init-param> <param-name>cors.allowOrigin</param-name> <param-value>*</param-value> </init-param> <init-param> <param-name>cors.supportedMethods</param-name> <param-value>GET, POST, HEAD, PUT, DELETE</param-value> </init-param> <init-param> <param-name>cors.supportedHeaders</param-name> <param-value>Accept, Origin, X-Requested-With, Content-Type, Last-Modified</param-value> </init-param> <init-param> <param-name>cors.exposedHeaders</param-name> <param-value>Set-Cookie</param-value> </init-param> <init-param> <param-name>cors.supportsCredentials</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>CORS</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
-
添加依賴
把cors-filter-1.7.0.wso2v1.jar
java-property-utils-1.9.jar
這兩個包放到
cas/WEB-INF/lib路徑下注:cors-filter-1.7.0.wso2v1.jar的原始下載路徑找不到了。這裏是我上傳的 cas實現單點登錄的相關依賴