跨域访问之CORS

简介:

出于安全性的考虑,用户代理(如浏览器)通常拒绝跨站的访问请求,但这会限制运行在用户代理的Web应用通过Ajax或者其他机制从另一个站点访问资源、获取数据。跨源资源共享(CORS)扩充了这个模型,通过使用自定义的HTTP响应头部(HTTP Response Header),通知浏览器资源可能被哪些跨源站点以何种HTTP方法获得。例如,浏览器在访问 http://example.com 站点的Web应用时,Web应用如果需要跨站访问另一站点的资源 http://hello-world.example,就需要使用该标准。http://hello-world.example 在HTTP的响应头部中定义 Access-Control-Allow-Origin: http://example.org,通知浏览器允许 http://example.org 跨源从 http://hello-world.example上获取资源。

 

 

 

CORS 图解

 

 

过程说明:

1 浏览器发出跨域访问请求,request header 携带 origin

2 服务器收到请求,服务器返回response header

3 浏览区检查reponse header ,如果Access-Control-Allow-Origin : 包含request header的Origin,那么浏览器认为这是安全操作,允许操作服务端返回的数据,否则浏览器认为非同源数据,不允许操作。

 

 

目前主流的浏览器基本都支持CORS规范,所以实现CORS跨域访问的关键就是Server 端返回的respone中添加 Access-Control-Allow-Origin:对应的请求origin.

 

Web API 如何实现跨域请求:

 

服务端代码

 

类说明:

 

 

  1. CorsAttribute:请求跨域的标记

 

  1. CorsMessageHandler:

拦截请求,确认请求是否允许跨域,如果允许,那么给response header 添加跨域请求 Access-Control-Allow-Origin,否则返回

{

  "Message": "Cross-origin request denied"

}

 

 

 

代码:

using System;using System.Collections.Generic;using System.Linq;using System.Net.Http;using System.Threading;using System.Threading.Tasks;using System.Web;using System.Web.Http;using System.Web.Http.Controllers;using System.Net;using System.Diagnostics; 

namespace Hbb0b0.MVC.CORS

{ 

    /// <summary>

    /// 跨域属性    /// 此处参考    /// asp.net webapi 2    ///

    /// </summary>

    public class CorsAttribute : Attribute

    { 

        /// <summary>

        /// 允许的站点列表        /// </summary>

        public Uri[] AllowOrigins

        {            get;            private set;

        } 

        /// <summary>

        /// 错误提示        /// </summary>

        public string ErrorMessage

        {            get;            set;

        } 

        /// <summary>

        /// 构造函数        /// </summary>

        /// <param name="allowOrigins"></param>

        public CorsAttribute(params string[] allowOrigins)

        {            this.AllowOrigins = (allowOrigins ?? new string[0]).Select(p => new Uri(p)).ToArray();

        } 

 

        /// <summary>

        /// 获取请求头信息,判断是否请求被允许跨域        /// </summary>

        /// <param name="request"></param>

        /// <param name="headers"></param>

        /// <returns></returns>

        public bool TryEvaluate(HttpRequestMessage request, out IDictionary<string, string> headers)

        {

            headers = null;            string origin = request.Headers.GetValues(HttpHeaderKeys.ORIGIN).FirstOrDefault();

            Uri originUrl = new Uri(origin);            if (this.AllowOrigins.Contains(originUrl))

            {

                headers = this.GenerateResposeHeaders(request);                return true;

            }            this.ErrorMessage = "Cross-origin request denied";            return false;

        } 

        /// <summary>

        /// 添加跨域许可请求头        /// </summary>

        /// <param name="request"></param>

        /// <returns></returns>

        private IDictionary<string, string> GenerateResposeHeaders(HttpRequestMessage request)

        {            string origin = request.Headers.GetValues("Origin").First();

            Dictionary<string, string> headers = new Dictionary<string, string>();

            headers.Add(HttpHeaderKeys.ACCESS_CONTROL_ALLOW_ORIGIN, origin);            if (request.IsPreflightRequest())

            {

                headers.Add(HttpHeaderKeys.ACCESS_CONTROL_ALLOW_ORIGIN, "*");                string requestHeaders = request.Headers.GetValues(HttpHeaderKeys.ACCESS_CONTROL_ALLOW_REQUEST_HEADERS).FirstOrDefault();                if (!string.IsNullOrEmpty(requestHeaders))

                {

                    headers.Add(HttpHeaderKeys.ACCESS_CONTROL_ALLOW_REQUEST_HEADERS, requestHeaders);

                }

            }            return headers;

        }

 

 

    }    /// <summary>

    /// Http Header keys    /// </summary>

    public class HttpHeaderKeys

    {        public const string ORIGIN = "Origin";        public const string ACCESS_CONTROL_ALLOW_ORIGIN = "Access-Control-Allow-Origin";        public const string ACCESS_CONTROL_ALLOW_REQUEST_METHOD = "Access-Control-Allow-Request-Methods";        public const string ACCESS_CONTROL_ALLOW_REQUEST_HEADERS = "Access-Control-Allow-Request-Headers";

    } 

 

    /// <summary>

    /// 判断是否是非简单跨域请求扩展方法    /// </summary>

    public static class HttpRequestMessageExtensions

    {        public static bool IsPreflightRequest(this HttpRequestMessage request)

        {            return request.Method == HttpMethod.Options &&

                      request.Headers.GetValues(HttpHeaderKeys.ORIGIN).Any() &&

                      request.Headers.GetValues(HttpHeaderKeys.ACCESS_CONTROL_ALLOW_REQUEST_METHOD).Any();

        }

    } 

    public class CorsMessageHandler : DelegatingHandler

    {        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)

        {            //Debugger.Break();
            HttpMethod originalMethod = request.Method;            bool isPreflightRequest = request.IsPreflightRequest();            if (isPreflightRequest)

            {                string method = request.Headers.GetValues(HttpHeaderKeys.ACCESS_CONTROL_ALLOW_REQUEST_HEADERS).FirstOrDefault();

                request.Method = new HttpMethod(method);

            }

 

            HttpConfiguration config = request.GetConfiguration();

 

            HttpControllerDescriptor description = config.Services.GetHttpControllerSelector().SelectController(request);

 

            HttpControllerContext context = new HttpControllerContext(request.GetConfiguration(), request.GetRouteData(), request)

            {

                ControllerDescriptor = description

            };

 

            HttpActionDescriptor actionDescriptor = config.Services.GetActionSelector().SelectAction(context);

 

            CorsAttribute corsAttribute = actionDescriptor.GetCustomAttributes<CorsAttribute>().FirstOrDefault();            if (corsAttribute == null)

            {                return base.SendAsync(request, cancellationToken);

            }

 

            IDictionary<string, string> headers;

            request.Method = originalMethod;

            HttpResponseMessage response = null;            //判断请求是否被授权

            bool authorized = corsAttribute.TryEvaluate(request, out headers); 

            //处理非简单跨域请求

            if (isPreflightRequest)

            {                if (authorized)

                {

                    response = new HttpResponseMessage(HttpStatusCode.OK);

                }

              

            }            //简单跨域请求

            else

            {                //如果授权,返回请求资源

                if (authorized)

                {

                    response = base.SendAsync(request, cancellationToken).Result;

                }                //非授权,返回错误信息

                else

                {

                    response = request.CreateErrorResponse(HttpStatusCode.BadRequest, corsAttribute.ErrorMessage);

                }

            } 

            //添加header

            if (headers!=null)

            {                foreach (var item in headers)

                {

                    response.Headers.Add(item.Key, item.Value);

                }

            } 

 

            return Task.FromResult<HttpResponseMessage>(response);

        }

    }

 

}

 

 

 

客户端代码:

 

@{

    Layout = null;

} 

<!DOCTYPE html>

 <html><head>

    <meta name="viewport" content="width=device-width" />

    <title>View</title>

    <script type="text/javascript" src="~/Scripts/jquery-1.10.2.js"></script>

    <script type="text/javascript">

        $(function () {

            $.ajax({

                type: "POST",

                async: false,

                url: "http://localhost/Hbb0b0.mvc.API/api/StudentAPI/",

                beforeSend: function (xmlHttpRequest) {                    //xmlHttpRequest.setRequestHeader("Origin", "http://hbb0b0notebook:51929/");
                },

                success: function (data) {                    //alert(data.name);
                    console.log(data);

                    getStudentList(data);

                },

 

                error: function () {

                    alert('fail');

                }

            });

 

        }); 

        function getStudentList(list) {

 

            console.debug("GetStudenListCors", list);

            $.each(list, function (index, student) { 

                var html = "<ul>";

                html += "<li> name:" + student.Name + "</li>"

                html += "</ul>";

                $("#divStudentList").append(html);

            });

        }    </script>

 </head><body>

    <div id="divStudentList">

 

    </div>

 

 </body></html>

 

运行结果

 

 

Request Header:

 

 

Response header:

 



















本文转自xsster51CTO博客,原文链接http://blog.51cto.com/12945177/1948520: ,如需转载请自行联系原作者


相关文章
|
2月前
|
存储 缓存 安全
oss跨域资源共享(CORS Configuration)
oss跨域资源共享(CORS Configuration)
55 4
|
3月前
|
前端开发 API 数据安全/隐私保护
Web前端开发中的跨域资源共享(CORS)解决方案
【2月更文挑战第5天】在Web前端开发中,跨域资源共享(CORS)是一个常见的挑战。本文将探讨CORS的概念和原理,并介绍一些常用的解决方案,包括服务器端配置和前端处理方法,帮助开发者更好地应对跨域请求问题。
117 4
|
3月前
|
前端开发 开发者
前端开发中的跨域资源共享(CORS)解决方案探讨
【2月更文挑战第2天】跨域资源共享(CORS)是前端开发中常见的问题,本文将深入探讨CORS的原理及解决方案,包括简单请求、预检请求以及常用的CORS解决方案,为前端开发者提供深入的理解和应对CORS问题的有效方法。
39 1
|
3月前
|
Java
springboot+cors跨域处理
springboot+cors跨域处理
26 0
|
3月前
|
前端开发 JavaScript API
探索前端开发中的跨域资源共享(CORS)
【2月更文挑战第3天】在前端开发中,跨域资源共享(CORS)是一个至关重要的话题。本文将深入探讨CORS的概念、工作原理以及如何在前端项目中正确配置和处理跨域请求,帮助开发者更好地理解和应用CORS技术。
29 7
|
3月前
|
前端开发 安全 JavaScript
前端开发中的跨域资源共享(CORS)机制
【2月更文挑战第3天】 在前端开发中,跨域资源共享(CORS)机制是一个重要的安全性问题。本文将介绍CORS的概念、原理和实现方式,并探讨在前端开发中如何处理跨域资源请求,以及如何提高网站的安全性。
|
2天前
|
缓存 前端开发 安全
Python web框架fastapi中间件的使用,CORS跨域详解
Python web框架fastapi中间件的使用,CORS跨域详解
|
9天前
|
JavaScript 前端开发 安全
JavaScript中跨域资源共享(CORS):原理和解决方案
【4月更文挑战第22天】本文介绍了JavaScript中跨域资源共享(CORS)的原理和解决方案。CORS借助HTTP头部字段允许跨域请求,核心是Access-Control-Allow-Origin响应头。解决方案包括:服务器端设置响应头(如使用Express.js的cors中间件)、使用代理服务器或JSONP。现代Web开发推荐使用CORS,因为它更安全、灵活,而JSONP已逐渐被淘汰。理解并正确实施CORS能提升Web应用性能和安全性。
|
2月前
|
缓存 安全 数据安全/隐私保护
在智能媒体服务中,跨域问题可以通过设置CORS(跨源资源共享)规则来解决
在智能媒体服务中,跨域问题可以通过设置CORS(跨源资源共享)规则来解决
19 4
|
2月前
|
JavaScript 安全 前端开发
js开发:请解释什么是跨域请求(CORS),以及如何解决跨域问题。
CORS是一种W3C标准,用于解决浏览器同源策略导致的跨域数据访问限制。它通过服务器在HTTP响应头添加标志允许特定源进行跨域请求。简单请求无需预检,而预检请求(OPTIONS)用于询问服务器是否接受非简单请求。服务器端配置响应头如`Access-Control-Allow-Origin`等实现CORS策略,客户端JavaScript则正常发起请求。若配置不当,浏览器将阻止跨域访问,保障安全。
24 2