web站點跨域白名單實踐

1.web.xml允許跨域名單與允許接口跨域配置


<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
	http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">

  <display-name>Archetype Created Web Application</display-name>

   ......
    <!--跨域處理開始 -->
    <filter>
        <filter-name>cros</filter-name>
        <filter-class>com.kuayu.filter.AccessFilter</filter-class>
        <init-param>
            <param-name>allowDomainRequestUrl</param-name>
            <param-value>
                /IPermissionService/getVersionSecret.htm,
                /IPermissionService/getVersionSecret
            </param-value>
        </init-param>
        <init-param>
            <param-name>allowDomain</param-name>
            <param-value>
                http://ces.bbc.com,
                http://ces.bbc.com:80,
                https://ces.bbc.com,
                https://ces.bbc.com:80
            </param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>cros</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <!--跨域處理結束 -->

   ......
</web-app>

2.跨域過濾器 AccessFilter 類

package com.kuayu.filter;


import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

@Component
public class AccessFilter extends HttpServlet implements Filter {

    private static final long serialVersionUID = 1L;
    /** 獲取允許跨域請求的URL */
    private Set<String> allowDomainRequestUrls = Collections.emptySet();
    /** 獲取允許跨域地址 */
    private Set<String> allowDomains = Collections.emptySet();

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        String allowDomainRequestUrl = filterConfig.getInitParameter("allowDomainRequestUrl");
        String allowDomain = filterConfig.getInitParameter("allowDomain");
        //獲取允許跨域請求的URL
        allowDomainRequestUrls = strSplitConvertList(allowDomainRequestUrl,",");
        //獲取允許跨域地址
        allowDomains = strSplitConvertList(allowDomain,",");
    }

    /**
     * String分隔
     * @param sourceStr
     * @param split
     * @return
     */
    private Set<String> strSplitConvertList(String sourceStr,String split){
        if(StringUtils.isBlank(sourceStr)){
            return Collections.emptySet();
        }
        String[] sourceArray = StringUtils.split(sourceStr,split);
        if(null == sourceArray || sourceArray.length == 0){
            return Collections.emptySet();
        }
        Set<String> sets = new HashSet<String>();
        for(String str : sourceArray){
            if(StringUtils.isNotBlank(str)){
                sets.add(str.trim());
            }
        }
        return sets;
    }

    /**
     * 是否包含請求Url
     * @param includeURLs
     * @param requestUrl
     * @return
     */
    public static boolean isIncludeUrl(Set<String> includeURLs, String requestUrl){
        if(CollectionUtils.isEmpty(includeURLs)){
            return Boolean.FALSE;
        }
        for(String includeURL : includeURLs){
            if(requestUrl.endsWith(includeURL)){
                return Boolean.TRUE;
            }
        }
        return Boolean.FALSE;
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;

        String requestUrl = httpRequest.getServletPath();
        //獲取請求的域名
        String originHeader= httpRequest.getHeader("Origin");
        //如果請求的域爲允許跨域的域名  且 請求URL爲允許跨域的URL
        if (allowDomains.contains(originHeader) && isIncludeUrl(allowDomainRequestUrls,requestUrl)){
            httpResponse.setHeader("Access-Control-Allow-Origin", originHeader);
            httpResponse.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
            httpResponse.setHeader("Access-Control-Max-Age", "3600");
            //表明服務器支持的所有頭信息字段
            httpResponse.setHeader("Access-Control-Allow-Headers","Origin,No-Cache,X-Requested-With,If-Modified-Since,Pragma,Last-Modified,Cache-Control,Expires,Content-Type,X-E4M-With,userId,token,X-Test-TOKEN");
            //如果要把Cookie發到服務器,需要指定Access-Control-Allow-Credentials字段爲true;
            httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
            httpResponse.setHeader("XDomainRequestAllowed","1");

           /* Cookie[] cookies = httpRequest.getCookies();
            // 然後迭代之
            String token = "USER_ID";
            if (cookies != null && cookies.length > 0) { //如果沒有設置過Cookie會返回null
                for (Cookie cookie : cookies) {
                    if(cookie.getName().equals("token")){
                        token = cookie.getValue();
                    }
                }
            }
            Cookie cookie = new Cookie("token",token);
            cookie.setPath("/");
            httpResponse.addCookie(cookie);*/
        }
        chain.doFilter(request, httpResponse);
    }
}

 

3.常見問題

a.針對特定接口跨域時,跨域邏輯需要放入過濾類中來實現,請求方式Object在到接口之前已被攔截了。

b.請求未跨域時, String originHeader= httpRequest.getHeader("Origin");獲取內容爲空對象。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章