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");获取内容为空对象。

 

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