การตั้งค่า Access-Control-Allow-Origin ใน ASP.Net MVC ซึ่งเป็นวิธีที่ง่ายที่สุด


206

ฉันมีวิธีการง่ายๆที่จะคืนค่า json มันทำงานบน ajax.example.com ฉันต้องการเข้าถึงสิ่งนี้จากเว็บไซต์อื่น someothersite.com

หากฉันพยายามโทรหาฉันจะได้รับสิ่งที่คาดหวัง ... :

Origin http://someothersite.com is not allowed by Access-Control-Allow-Origin.

ฉันรู้วิธีที่จะหลีกเลี่ยงสองวิธีนี้: JSONPและสร้างHttpHandler ที่กำหนดเองเพื่อตั้งค่าส่วนหัว

ไม่มีวิธีที่ง่ายกว่านี้ไหม?

เป็นไปไม่ได้หรือที่การกระทำอย่างง่าย ๆ ในการกำหนดรายการของต้นกำเนิดที่ได้รับอนุญาต - หรือเป็นการง่ายสำหรับทุกคน? อาจเป็นตัวกรองการกระทำหรือไม่

เหมาะสมที่สุดคือ ... :

return json(mydata, JsonBehaviour.IDontCareWhoAccessesMe);

1
โปรดดูที่นี่สำหรับ vNext และ MVC6: neelbhatt40.wordpress.com/2015/09/10/…
Neel

คำตอบ:


381

สำหรับ ASP.NET MVC คอนโทรลเลอร์ธรรมดา

สร้างคุณสมบัติใหม่

public class AllowCrossSiteJsonAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        filterContext.RequestContext.HttpContext.Response.AddHeader("Access-Control-Allow-Origin", "*");
        base.OnActionExecuting(filterContext);
    }
}

แท็กการกระทำของคุณ:

[AllowCrossSiteJson]
public ActionResult YourMethod()
{
    return Json("Works better?");
}

สำหรับ ASP.NET Web API

using System;
using System.Web.Http.Filters;

public class AllowCrossSiteJsonAttribute : ActionFilterAttribute
{
    public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
    {
        if (actionExecutedContext.Response != null)
            actionExecutedContext.Response.Headers.Add("Access-Control-Allow-Origin", "*");

        base.OnActionExecuted(actionExecutedContext);
    }
}

ติดแท็กคอนโทรลเลอร์ API ทั้งหมด:

[AllowCrossSiteJson]
public class ValuesController : ApiController
{

หรือการเรียก API แต่ละรายการ:

[AllowCrossSiteJson]
public IEnumerable<PartViewModel> Get()
{
    ...
}

สำหรับ Internet Explorer <= v9

IE <= 9 ไม่รองรับ CORS ฉันได้เขียนจาวาสคริปต์ที่จะกำหนดเส้นทางคำขอเหล่านั้นโดยอัตโนมัติผ่านพร็อกซี มันโปร่งใสทั้งหมด 100% (คุณต้องใส่พร็อกซีและสคริปต์ของฉันด้วย)

ดาวน์โหลดโดยใช้ nuget corsproxyและทำตามคำแนะนำที่มีให้

โพสต์บล็อก | รหัสแหล่งที่มา


8
! ที่น่าตื่นตาตื่นใจ ฉัน luv MVC + U!
Piotr Kula

2
ด้วยความน่าสะพรึงกลัวของวิธีแก้ปัญหานี้
BraveNewMath

3
คุณสามารถขยายคุณสมบัติเพื่อรับต้นกำเนิดที่เฉพาะเจาะจงได้อย่างง่ายดายหากคุณต้องการ จำกัด CORS ไว้ในโดเมนของคุณเอง
Petrus Theron

2
คุณควรจะเพิ่มสิ่งนี้ลงใน RegisterHttpFilters ใน App_Start \ FilterConfig ของคุณถูกต้องไหม? การทำเช่นนั้นจะนำไปใช้กับตัวควบคุม Api ทั้งหมดในโครงการของคุณ การรวมสิ่งนี้ด้วยความคิดเห็นของ pate ด้านบนคุณสามารถ จำกัด CORS ให้กับโดเมนของคุณสำหรับตัวควบคุมทั้งหมด
bdwakefield

9
ฉันเพิ่งอัปเดตโครงการเป็น MVC 5 และพยายามทำสิ่งนี้ แม้การเพิ่มส่วนหัวในตัวกรองก็ไม่สามารถใช้งานได้ เมื่อฉันดูคำขอในเครือข่ายส่วนหัวจะไม่ปรากฏในการตอบสนอง มีอะไรอีกบ้างที่ต้องทำเพื่อให้มันใช้งานได้
Kneemin

121

หากคุณใช้ IIS 7+ คุณสามารถวางไฟล์ web.config ลงในรูทของโฟลเดอร์ด้วยสิ่งนี้ได้ในส่วน system.webServer:

<httpProtocol>
   <customHeaders>
      <clear />
      <add name="Access-Control-Allow-Origin" value="*" />
   </customHeaders>
</httpProtocol>

ดู: http://msdn.microsoft.com/en-us/library/ms178685.aspx และ: http://enable-cors.org/#how-iis7


1
ฉันจำไม่ได้ว่าทำไมอีกต่อไป แต่วิธีนี้ใช้ไม่ได้กับ IIS 7+ ทุกครั้ง
LaundroMatt

อืมมม เหตุผลเดียวที่ฉันคิดว่ามันจะไม่ทำงานคือถ้าคำขอมาจากเบราว์เซอร์ที่ไม่ใช่ CORS แต่ฉันจะตรวจสอบต่อไป
sellmeadog

29
นอกจากนี้สิ่งนี้จะทำให้เว็บไซต์ทั้งหมดเป็นมิตรกับ CORS หากใครบางคนต้องการที่จะทำเครื่องหมายเพียงการกระทำเดียวหรือควบคุมเป็นมิตรกับ CORS แล้วคำตอบที่ได้รับการยอมรับจะดีกว่ามาก
Lev Dubinets

1
หากคุณเห็นส่วนASP.Netจะมีคำใบ้ : "หมายเหตุ: วิธีนี้เข้ากันได้กับ IIS6, IIS7 Classic Mode และ IIS7 Integrated Mode"
รู้บัส

1
ฉันกำลังประสบปัญหาข้ามโดเมนเมื่อฉันเผยแพร่แอปของฉันในสภาพแวดล้อมของ SharePoint เมื่อฉันเรียกใช้แอปของฉันในสภาพแวดล้อมท้องถิ่นแอพของฉันจะทำงานได้ดี แต่เมื่อฉันเผยแพร่ในสีฟ้าไปยังไซต์ SharePoint ของฉันมันจะเปลี่ยนเส้นทางไปยังหน้าข้อผิดพลาดในการโทรแบบฟอร์ม Ajax.Begin ฉันลองใช้วิธีนี้ แต่ไม่ได้ผลสำหรับฉัน มีทางเลือกอื่นอีกไหม?
Jyotsna Wadhwani

22

ฉันวิ่งเข้าไปในปัญหาที่เบราว์เซอร์ปฏิเสธที่จะให้บริการขึ้นเนื้อหาว่าได้เรียกเมื่อร้องขอผ่านในคุกกี้ (เช่น XHR มีของwithCredentials=true) และเว็บไซต์ที่มีการตั้งค่าให้Access-Control-Allow-Origin *(ข้อผิดพลาดใน Chrome คือ "ไม่สามารถใช้อักขระตัวแทนใน Access-Control-Allow-Origin เมื่อการตั้งค่าสถานะหนังสือรับรองเป็นจริง")

จากคำตอบของ @jgauffin ฉันได้สร้างสิ่งนี้ขึ้นมาซึ่งเป็นวิธีการแก้ไขการตรวจสอบความปลอดภัยของเบราว์เซอร์นั้น

public class AllowCrossSiteJsonAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        // We'd normally just use "*" for the allow-origin header, 
        // but Chrome (and perhaps others) won't allow you to use authentication if
        // the header is set to "*".
        // TODO: Check elsewhere to see if the origin is actually on the list of trusted domains.
        var ctx = filterContext.RequestContext.HttpContext;
        var origin = ctx.Request.Headers["Origin"];
        var allowOrigin = !string.IsNullOrWhiteSpace(origin) ? origin : "*";
        ctx.Response.AddHeader("Access-Control-Allow-Origin", allowOrigin);
        ctx.Response.AddHeader("Access-Control-Allow-Headers", "*");
        ctx.Response.AddHeader("Access-Control-Allow-Credentials", "true");
        base.OnActionExecuting(filterContext);
    }
}

นี่เป็นประโยชน์อย่างยิ่งขอบคุณ
cklimowski

15

ง่ายมากเพียงแค่เพิ่มลงใน web.config

<system.webServer>
  <httpProtocol>
    <customHeaders>
      <add name="Access-Control-Allow-Origin" value="http://localhost" />
      <add name="Access-Control-Allow-Headers" value="X-AspNet-Version,X-Powered-By,Date,Server,Accept,Accept-Encoding,Accept-Language,Cache-Control,Connection,Content-Length,Content-Type,Host,Origin,Pragma,Referer,User-Agent" />
      <add name="Access-Control-Allow-Methods" value="GET, PUT, POST, DELETE, OPTIONS" />
      <add name="Access-Control-Max-Age" value="1000" />
    </customHeaders>
  </httpProtocol>
</system.webServer>

ใน Origin ให้โดเมนทั้งหมดที่มีการเข้าถึงเว็บเซิร์ฟเวอร์ของคุณในส่วนหัวให้ส่วนหัวที่เป็นไปได้ทั้งหมดที่ ajax http ร้องขอใด ๆ สามารถใช้ในวิธีการใส่วิธีการทั้งหมดที่คุณอนุญาตบนเซิร์ฟเวอร์ของคุณ

ความนับถือ :)


การเพิ่ม "การอนุญาต" ใน Access-Control-Allow-Headers อาจมีประโยชน์หากคุณต้องการใช้แบบสอบถามที่ได้รับอนุญาต
หยุด

9

บางครั้ง OPTIONS กริยาก็ทำให้เกิดปัญหาเช่นกัน

เพียงแค่: อัปเดต web.config ของคุณด้วยสิ่งต่อไปนี้

<system.webServer>
    <httpProtocol>
        <customHeaders>
          <add name="Access-Control-Allow-Origin" value="*" />
          <add name="Access-Control-Allow-Headers" value="Origin, X-Requested-With, Content-Type, Accept" />
        </customHeaders>
    </httpProtocol>
</system.webServer>

และอัปเดตส่วนหัวเว็บเซอร์ / คอนโทรลเลอร์ด้วย httpGet และ httpOptions

// GET api/Master/Sync/?version=12121
        [HttpGet][HttpOptions]
        public dynamic Sync(string version) 
        {

BTW ในไซต์ความจริงคุณต้องเพิ่ม * ในการตั้งค่าขั้นสูงของระบบในส่วนความปลอดภัย
Bishoy Hanna

ไฟล์ใดบ้างที่ฉันจำเป็นต้องอัพเดตส่วนหัวคอนโทรลเลอร์?
user3281466


5

เพิ่มบรรทัดนี้ในวิธีการของคุณหากคุณใช้ API

HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*"); 

4

บทช่วยสอนนี้มีประโยชน์มาก หากต้องการสรุปสั้น ๆ :

  1. ใช้แพ็คเกจ CORS ที่มีอยู่บน Nuget: Install-Package Microsoft.AspNet.WebApi.Cors

  2. ในWebApiConfig.csไฟล์ของคุณเพิ่มconfig.EnableCors()ไปยังRegister()วิธีการ

  3. เพิ่มแอตทริบิวต์ให้กับคอนโทรลเลอร์ที่คุณต้องใช้ในการจัดการคอร์:

[EnableCors(origins: "<origin address in here>", headers: "*", methods: "*")]


ฉันต้องใช้วิธีนี้เพราะฉันจำเป็นต้องตั้งค่าส่วนหัวที่กำหนดเองในคำขอของฉันและวิธีการแอตทริบิวต์ที่กำหนดเองไม่สามารถใช้งานได้กับการร้องขอล่วงหน้าของเบราว์เซอร์ ดูเหมือนว่าจะทำงานได้ในทุกกรณี
lehn0058

3
    public ActionResult ActionName(string ReqParam1, string ReqParam2, string ReqParam3, string ReqParam4)
    {
        this.ControllerContext.HttpContext.Response.Headers.Add("Access-Control-Allow-Origin","*");
         /*
                --Your code goes here --
         */
        return Json(new { ReturnData= "Data to be returned", Success=true }, JsonRequestBehavior.AllowGet);
    }

2

มีหลายวิธีที่เราสามารถส่งผ่าน Access-Control-Expose-Headers

  • ตามที่ jgauffin ได้อธิบายไว้เราสามารถสร้างคุณลักษณะใหม่ได้
  • ตามที่ LaundroMatt ได้อธิบายไว้เราสามารถเพิ่มไฟล์ web.config
  • อีกวิธีคือเราสามารถเพิ่มรหัสด้านล่างในไฟล์ webApiconfig.cs

    config.EnableCors (EnableCorsAttribute ใหม่ (" ", ส่วนหัว: " ", วิธีการ: "*", exposedHeaders: "TestHeaderToExpose") {CompatibleCredentials = true});

หรือเราสามารถเพิ่มรหัสด้านล่างในไฟล์ Global.Asax

protected void Application_BeginRequest()
        {
            if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
            {
                //These headers are handling the "pre-flight" OPTIONS call sent by the browser
                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "*");
                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Credentials", "true");
                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "http://localhost:4200");
                HttpContext.Current.Response.AddHeader("Access-Control-Expose-Headers", "TestHeaderToExpose");
                HttpContext.Current.Response.End();
            }
        }

ฉันได้เขียนไว้สำหรับตัวเลือก โปรดแก้ไขเช่นเดียวกับความต้องการของคุณ

Happy Coding !!


1

หลังจากดิ้นรนตลอดทั้งคืนในที่สุดฉันก็สามารถทำงานได้ หลังจากแก้จุดบกพร่องบางอย่างฉันพบปัญหาที่ฉันเดินเข้าไปก็คือลูกค้าของฉันกำลังส่งคำขอตัวเลือก preflight ที่เรียกว่าเพื่อตรวจสอบว่าใบสมัครได้รับอนุญาตให้ส่งคำขอโพสต์กับแหล่งกำเนิดวิธีการและส่วนหัวให้ ฉันไม่ต้องการใช้ Owin หรือ APIController ดังนั้นฉันจึงเริ่มขุดและคิดหาวิธีแก้ปัญหาต่อไปนี้ด้วย ActionFilterAttribute โดยเฉพาะอย่างยิ่งส่วน "Access-Control-Allow-Headers" เป็นสิ่งสำคัญมากเนื่องจากส่วนหัวที่กล่าวถึงจะต้องตรงกับส่วนหัวที่คำขอของคุณจะส่ง

using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace MyNamespace
{
    public class AllowCrossSiteJsonAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            HttpRequest request = HttpContext.Current.Request;
            HttpResponse response = HttpContext.Current.Response;

            // check for preflight request
            if (request.Headers.AllKeys.Contains("Origin") && request.HttpMethod == "OPTIONS")
            {
                response.AppendHeader("Access-Control-Allow-Origin", "*");
                response.AppendHeader("Access-Control-Allow-Credentials", "true");
                response.AppendHeader("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE");
                response.AppendHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, X-RequestDigest, Cache-Control, Content-Type, Accept, Access-Control-Allow-Origin, Session, odata-version");
                response.End();
            }
            else
            {
                HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);
                HttpContext.Current.Response.Cache.SetNoStore();

                response.AppendHeader("Access-Control-Allow-Origin", "*");
                response.AppendHeader("Access-Control-Allow-Credentials", "true");
                if (request.HttpMethod == "POST")
                {
                    response.AppendHeader("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE");
                    response.AppendHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, X-RequestDigest, Cache-Control, Content-Type, Accept, Access-Control-Allow-Origin, Session, odata-version");
                }

                base.OnActionExecuting(filterContext);
            }
        }
    }
}

ในที่สุดวิธีการกระทำ MVC ของฉันก็เป็นเช่นนี้ สิ่งสำคัญที่นี่ยังพูดถึงตัวเลือก HttpVerbs เพราะมิฉะนั้นคำขอ preflight จะล้มเหลว

[AcceptVerbs(HttpVerbs.Post | HttpVerbs.Options)]
[AllowCrossSiteJson]
public async Task<ActionResult> Create(MyModel model)
{
    return Json(await DoSomething(model));
}

0

ใน Web.config ให้ป้อนข้อมูลต่อไปนี้

<system.webServer>
<httpProtocol>
  <customHeaders>
    <clear />     
    <add name="Access-Control-Allow-Credentials" value="true" />
    <add name="Access-Control-Allow-Origin" value="http://localhost:123456(etc)" />
  </customHeaders>
</httpProtocol>

0

ถ้าคุณใช้ IIS ผมขอแนะนำให้พยายามโมดูล IIS ล ธ
ง่ายต่อการกำหนดค่าและใช้งานได้กับคอนโทรลเลอร์ทุกประเภท

นี่คือตัวอย่างของการกำหนดค่า:

    <system.webServer>
        <cors enabled="true" failUnlistedOrigins="true">
            <add origin="*" />
            <add origin="https://*.microsoft.com"
                 allowCredentials="true"
                 maxAge="120"> 
                <allowHeaders allowAllRequestedHeaders="true">
                    <add header="header1" />
                    <add header="header2" />
                </allowHeaders>
                <allowMethods>
                     <add method="DELETE" />
                </allowMethods>
                <exposeHeaders>
                    <add header="header1" />
                    <add header="header2" />
                </exposeHeaders>
            </add>
            <add origin="http://*" allowed="false" />
        </cors>
    </system.webServer>

0

ฉันใช้ DotNet Core MVC และหลังจากต่อสู้ไปสองสามชั่วโมงด้วยแพ็คเกจ nuget, Startup.cs, คุณสมบัติและสถานที่นี้ฉันเพิ่งเพิ่มสิ่งนี้ไปยังแอ็คชั่น MVC:

Response.Headers.Add("Access-Control-Allow-Origin", "*");

ฉันรู้ว่านี่เป็น clunky สวย แต่มันคือทั้งหมดที่ฉันต้องการและไม่มีอะไรอื่นที่ต้องการเพิ่มส่วนหัวเหล่านั้น ฉันหวังว่านี่จะช่วยคนอื่นได้!

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.