跨域的几种实现方式(JSONP,Proxy,CORS)

同源策略

同源策略是一个重要的安全策略,它用于限制一个origin的文档或者它加载的脚本如何能与另一个源的资源进行交互。它能帮助阻隔恶意文档,减少可能被攻击的媒介。

同源的定义

如果两个 URL 的 protocolport host 都相同的话,则这两个 URL 是同源。

源的更改

满足某些限制条件的情况下,页面是可以修改它的源。脚本可以将 document.domain 的值设置为其当前域或其当前域的父域。
例如:
假设 http://store.company.com/dir/other.html 文档中的一个脚本执行以下语句:

document.domain = "company.com";

然而company.com 不能设置为 othercompany.com,因为它不是 company.com 的父域。

源的继承?

跨域方法

实现跨域请求有以下方法:JSONP,Proxy,CORS,Nginx,Socket...

JSONP:

JSONP实现原理:利用script标签不受同源策略限制,在页面动态添加script,script标签的src属性设成api地址,并将回调函数名以get方式告诉后端,后端将数据以参数的形式返回
JSONP的优缺点:只能发get请求、不安全、老式浏览器支持性好

Proxy:

通过代理服务器转发请求,实现跨域

CORS

老版浏览器不支持、支持所有谓词请求,推荐使用

带策略的CORS 和中间件

CORS中间件处理跨域请求。下面的代码允许指定的源能对整个应用进行跨域请求

案例:

CORS中间件处理跨域请求。下面的代码允许指定的源能对整个应用进行跨域请求
这个代码会把CORS策略通过CORS中间件应用到这个应用的所有终端(endpoints);即把跨域作用到整个应用

指定域名可以跨域请求:

public void ConfigureServices(IServiceCollection services)
        {
         
                string[] origins = new string[] { "http://*.fan.com", "https://*.fan.com", "http://*.fan.net", "https://*.fan.net" };
                services.AddCors(option => option.AddPolicy("cors", policy => policy
                    .AllowAnyHeader()//允许所有的请求头
                                     //.WithHeaders(HeaderNames.ContentType, "x-custom-header");//要允许一个CORS请求中指定的请求头,可以使用 WithHeaders 来指定
                    .AllowAnyMethod()//允许所有Method
                    .SetIsOriginAllowedToAllowWildcardSubdomains()//使可以匹配一个配置的带通配符的域名
                    .WithOrigins(origins) //指定来源域名
                    .AllowCredentials() //允许浏览器在跨域请求中发送证书
                ));
         }
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IHostApplicationLifetime applicationLifetime, ILogger<Startup> logger , ElasticSearch elasticSearch)
        {
            app.UseCors("cors");//注意:1.UseCors必须在UseMvc之前被调用;2. URL末尾不能加/ ;这个url指的是 builder.WithOrigins(url)中的url
            }

不做限制,允许所有域名跨域请求:

services.AddCors(option => option.AddPolicy("cors", policy => policy
                        .AllowAnyHeader()
                        .AllowAnyMethod()
                        .SetIsOriginAllowed(_ => true) //不做任何限制
                        .AllowCredentials()
                    )
                );

使用[EnableCors]属性设置允许跨域

[EnableCors]属性提供了另一种方式设置跨域。即可以只设置选择的终端,而不是所有的终端.
这里不同于上面的那种方式,上面的方式是应用的所有终端都会被设置允许跨域;
使用[EnableCors]来指定默认的策略,而[EnableCors("{Policy String}")] 指定了特定的策略;
[DisableCors]属性可以禁止CORS;

    [EnableCors("AnotherPolicy")]
    [HttpGet]
    public ActionResult<IEnumerable<string>> Get()
    {
        return new string[] { "green widget", "red widget" };
    }

CORS 策略(Policy)的选项:

  • 设置允许的访问源
  • 设置允许的HTTP methods
  • 设置允许的请求头(request header)
  • 设置暴露的响应头(response header)
  • 跨不同源请求的证书(Credentials)
  • 设置过期时间

SetIsOriginAllowedToAllowWildcardSubdomains:设置策略的 IsOriginAllowed 属性,使可以匹配一个配置的带通配符的域名
AllowAnyMethod:设置允许的HTTP methods
WithHeaders:要允许一个CORS请求中指定的请求头,可以使用 WithHeaders 来指定
AllowAnyHeader:允许所有的请求头
withCredentials:允许在跨域请求中发送证书
WithExposedHeaders:暴露指定的响应头

注意:如果 Access-Control-Allow-Credentials 头部出现了,则意味着 设置为所有的源 (setting origin to " * ")会失效。

JSONP

过滤器:

   public class JsonpFilter : IActionFilter
    {
        public void OnActionExecuting(ActionExecutingContext context)
        {
            // do something before the action executes
        }

        public void OnActionExecuted(ActionExecutedContext context)
        {
            // do something after the action executes
            //if (context.HttpContext.Request.Headers.FirstOrDefault(x => x.Key == "X-Requested-With").Value == "XMLHttpRequest")
            //{
            //    context.Result = new JsonpResult(new JsonResult(context.Exception), context.HttpContext.Request.Query["callback"]);
            //    return;
            //}
            if (context.Exception != null || context.Result == null || !(context.Result is JsonResult)) return;
            if (context.HttpContext.Request.Method != "GET") return;
            if (string.IsNullOrEmpty(context.HttpContext.Request.Query["callback"])) return;
            context.Result = new JsonpResult(context.Result as JsonResult, context.HttpContext.Request.Query["callback"]);
        }



        public class JsonpResult : ActionResult
        {
            private static readonly string DefaultContentType = new MediaTypeHeaderValue("application/json")
            {
                CharSet = "utf-8"
            }.ToString();
            private readonly JsonResult result = null;
            private readonly string callback;

            public JsonpResult(JsonResult p, string callback)
            {
                result = p;
                this.callback = callback;
            }

            public override Task ExecuteResultAsync(ActionContext context)
            {
                if (result == null)
                {
                    throw new ArgumentNullException(nameof(result));
                }

                if (context == null)
                {
                    throw new ArgumentNullException(nameof(context));
                }

                var services = context.HttpContext.RequestServices;
                var Options = services.GetRequiredService<IOptions<MvcJsonOptions>>().Value;
                var writerFactory = services.GetRequiredService<IHttpResponseStreamWriterFactory>();
                var _charPool = new JsonArrayPool<char>(services.GetRequiredService<ArrayPool<char>>());
                var response = context.HttpContext.Response;


                ResponseContentTypeHelper.ResolveContentTypeAndEncoding(
                    result.ContentType,
                    response.ContentType,
                    DefaultContentType,
                    out var resolvedContentType,
                    out var resolvedContentTypeEncoding);

                response.ContentType = resolvedContentType;
                if (result.StatusCode != null)
                {
                    response.StatusCode = result.StatusCode.Value;
                }
                var serializerSettings = result.SerializerSettings ?? Options.SerializerSettings;
                using (var writer = writerFactory.CreateWriter(response.Body, resolvedContentTypeEncoding))
                {
                    var jsonSerializer = JsonSerializer.Create(serializerSettings);
                    using (var jsonWriter = new JsonTextWriter(writer))
                    {

                        jsonWriter.ArrayPool = _charPool;
                        jsonWriter.CloseOutput = false;
                        jsonWriter.AutoCompleteOnClose = false;
                        jsonWriter.WriteRaw(callback + "(");
                        jsonSerializer.Serialize(jsonWriter, result.Value);
                        jsonWriter.WriteRaw(");");
                    }
                }
                return Task.CompletedTask;
            }
        }
    }

参考:
https://www.cnblogs.com/Vincent-yuan/p/10801513.html
https://docs.microsoft.com/zh-cn/aspnet/core/security/cors

posted @ 2020-07-15 14:03  .Neterr  阅读(1031)  评论(0编辑  收藏  举报