65.9K
CodeProject 正在变化。 阅读更多。
Home

在 ASP.NET Core 中启用跨域资源共享 (CORS)

starIconstarIconstarIconstarIconstarIcon

5.00/5 (6投票s)

2016 年 10 月 27 日

CPOL

3分钟阅读

viewsIcon

34834

downloadIcon

277

在本文中,我们将重点介绍如何在 ASP.NET Core 应用程序中启用 CORS,了解 CORS 策略,以及如何通过不同的源共享资源。

本文将讨论以下主题

  • 什么是 CORS?
  • 创建 .NET Core WebApi 应用程序
    • 添加包
    • 添加数据库连接
    • 启用 CORS
  • 发布到 IIS
  • 通过 .NET Core 示例应用程序共享

引言

首先让我们了解一下 CORS,来自 Wikipedia,跨域资源共享 (CORS) 是一种机制,允许从源资源域之外的另一个域请求网页上受限制的资源(例如,字体)。从 docs.asp.net 获取更多详细信息。 好吧,让我们从一个示例应用程序开始我们的主题

创建新应用程序

打开 Visual Studio 2015,然后转到顶部菜单并单击“文件” > “新建” > “项目”。

core_4

选择 Web API 模板。

core_5

最后,将出现 .NET Core 欢迎页面。 阅读有关 .NET Core 的更多信息。

core_6

首先,我们需要将所需的包添加到示例应用程序中,这里我们将下面列出的那些包添加到 project.json 文件中。 将所有这些包放入我们的项目配置文件后,它们将自动添加到我们的应用程序中。

project.json
//EntityFrameworkCore
"Microsoft.EntityFrameworkCore.SqlServer": "1.0.1",
"Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview2-final",
"Microsoft.EntityFrameworkCore.SqlServer.Design": "1.0.1",
"Microsoft.EntityFrameworkCore": "1.0.1",

//Cross Origin Resource Sharing
"Microsoft.AspNetCore.Cors": "1.0.0"

现在让我们将数据库连接添加到我们的应用程序。 打开 appsettings.json 文件,我们已将数据库连接字符串放在此处,您可以从下面的代码部分看到。

appsettings.json
{
  "ConnectionStrings": {
    "dbConn": "Server=DESKTOP-JAKRV2S;Database=PhoneBook;Trusted_Connection=True;
    MultipleActiveResultSets=true"
  },
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Debug",
      "System": "Information",
      "Microsoft": "Information"
    }
  }
}

之后,我们需要在 Startup.cs 的应用程序中间件中调用它。

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    
    //Add database services.
    var connectionString = this.Configuration.GetConnectionString("dbConn");
    services.AddDbContext<PhoneBookContext>
    (options => options.UseSqlServer(connectionString));
}

现在,我们将向示例 API 应用程序添加并启用 CORS。 从解决方案资源管理器中打开 Startup.cs 文件,正如您所看到的,我已在 ConfigureServices 方法中添加了 CORS 服务,以通过在运行时调用来启用它。 在这里,我们还通过使用 CorsPolicyBuilder 指定了不同的 CORS 启用策略。 您可以使用此示例应用程序启用不同类型进行测试。

Startup.cs:ConfigureServices

services.AddCors(
    options => options.AddPolicy("AllowCors",
    builder =>
    {
        builder
        //.WithOrigins("https://:4456") //AllowSpecificOrigins;
        //.WithOrigins("https://:4456", 
        "https://:4457") //AllowMultipleOrigins;
        .AllowAnyOrigin() //AllowAllOrigins;

        //.WithMethods("GET") //AllowSpecificMethods;
        //.WithMethods("GET", "PUT") //AllowSpecificMethods;
        //.WithMethods("GET", "PUT", "POST") //AllowSpecificMethods;
        .WithMethods("GET", "PUT", 
        "POST", "DELETE") //AllowSpecificMethods;
        //.AllowAnyMethod() //AllowAllMethods;

        //.WithHeaders("Accept", "Content-type", "Origin", "X-Custom-Header");  
        //AllowSpecificHeaders;
        .AllowAnyHeader(); //AllowAllHeaders;
    })
);

让我们分离代码

通过 Origin:使用全部、多个或特定 Origin 启用 CORS

允许特定 Origin
builder.WithOrigins("https://:4456")
允许多个 Origin
builder.WithOrigins("https://:4456", "https://:4457")
允许所有 Origin
builder.AllowAnyOrigin()

通过 Methods:使用全部、多个或特定 Methods 启用 CORS

允许特定 Methods
builder.WithMethods("GET", "PUT", "POST", "DELETE")
允许所有 Methods
builder.AllowAnyMethod()

通过 Headers使用全部或特定 Headers 启用 CORS

允许特定 Headers
builder.WithHeaders("Accept", "Content-type", "Origin", "X-Custom-Header")
允许所有 Headers
builder.AllowAnyHeader()

之后,我们使用扩展方法“UseCors”为您的应用程序启用了 CORS。

Startup.cs:Configure

//Enable CORS policy "AllowCors"
app.UseCors("AllowCors");

最后是完整的 Startup.cs:

public class Startup
{
    public Startup(IHostingEnvironment env)
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(env.ContentRootPath)
            .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
            .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);

        if (env.IsEnvironment("Development"))
        {
            // This will push telemetry data through Application Insights pipeline faster, 
            // allowing you to view results immediately.
            builder.AddApplicationInsightsSettings(developerMode: true);
        }

        builder.AddEnvironmentVariables();
        Configuration = builder.Build();
    }

    public IConfigurationRoot Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container
    public void ConfigureServices(IServiceCollection services)
    {

        //Add database services.
        var connectionString = this.Configuration.GetConnectionString("dbConn");
        services.AddDbContext<PhoneBookContext>
        (options => options.UseSqlServer(connectionString));

        // Add framework services.
        services.AddApplicationInsightsTelemetry(Configuration);

        services.AddMvc();

        //Add CORS services.
        //services.Configure<MvcOptions>(options =>
        //{
        //    options.Filters.Add
        //    (new CorsAuthorizationFilterFactory("AllowSpecificOrigin"));
        //});

        services.AddCors(
            options => options.AddPolicy("AllowCors",
            builder =>
            {
                builder
                //.WithOrigins("https://:4456") //AllowSpecificOrigins;
                //.WithOrigins("https://:4456", "https://:4457") 
                //AllowMultipleOrigins;
                .AllowAnyOrigin() //AllowAllOrigins;

                //.WithMethods("GET") //AllowSpecificMethods;
                //.WithMethods("GET", "PUT") //AllowSpecificMethods;
                //.WithMethods("GET", "PUT", "POST") 
                //AllowSpecificMethods;
                .WithMethods("GET", "PUT", "POST", "DELETE") 
                //AllowSpecificMethods;
                //.AllowAnyMethod() //AllowAllMethods;

                //.WithHeaders("Accept", 
                //"Content-type", "Origin", "X-Custom-Header");  
                //AllowSpecificHeaders;
                .AllowAnyHeader(); //AllowAllHeaders;
            })
        );
    }

    // This method gets called by the runtime. 
    // Use this method to configure the HTTP request pipeline
    public void Configure
    (IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        loggerFactory.AddConsole(Configuration.GetSection("Logging"));
        loggerFactory.AddDebug();

        app.UseApplicationInsightsRequestTelemetry();

        app.UseApplicationInsightsExceptionTelemetry();

        app.UseMvc();

        //Enable CORS policy "AllowCors"
        app.UseCors("AllowCors");
    }
}

MVC WebApi:这是必需的命名空间列表。

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Cors;
using CrossOrigin.WebService.Models.DbEntities;
using Microsoft.EntityFrameworkCore;

API 控制器:在这里,我们在 APiController 上应用特定的 CORS 策略。 它也可以应用于基于每个操作,或全局应用于所有控制器。

[EnableCors("AllowCors"), Route("api/[controller]")]
public class ContactController : Controller
{
    private PhoneBookContext _ctx = null;
    public ContactController(PhoneBookContext context)
    {
        _ctx = context;
    }

    // GET: api/Contact/GetContact
    [HttpGet("GetContact"), Produces("application/json")]
    public async Task<object> GetContact()
    {
        List<Contacts> contacts = null;
        object result = null;
        try
        {
            using (_ctx)
            {
                contacts = await _ctx.Contacts.ToListAsync();
                result = new
                {
                    contacts
                };
            }
        }
        catch (Exception ex)
        {
            ex.ToString();
        }
        return contacts;
    }

    // GET api/Contact/GetContactByID/5
    [HttpGet("GetContactByID/{id}"), Produces("application/json")]
    public async Task<Contacts> GetContactByID(int id)
    {
        Contacts contact = null;
        try
        {
            using (_ctx)
            {
                contact = await _ctx.Contacts.FirstOrDefaultAsync(x => x.ContactId == id);
            }
        }
        catch (Exception ex)
        {
            ex.ToString();
        }
        return contact;
    }

    // POST api/Contact/PostContact
    [HttpPost, Route("PostContact"), Produces("application/json")]
    public async Task<object> PostContact([FromBody]Contacts model)
    {
        object result = null; string message = "";
        if (model == null)
        {
            return BadRequest();
        }
        using (_ctx)
        {
            using (var _ctxTransaction = _ctx.Database.BeginTransaction())
            {
                try
                {
                    _ctx.Contacts.Add(model);
                    await _ctx.SaveChangesAsync();
                    _ctxTransaction.Commit();
                    message = "Saved Successfully";
                }
                catch (Exception e)
                {
                    _ctxTransaction.Rollback();
                    e.ToString();
                    message = "Saved Error";
                }

                result = new
                {
                    message
                };
            }
        }
        return result;
    }

    // PUT api/Contact/PutContact/5
    [DisableCors, HttpPut, Route("PutContact/{id}")]
    public async Task<object> PutContact(int id, [FromBody]Contacts model)
    {
        object result = null; string message = "";
        if (model == null)
        {
            return BadRequest();
        }
        using (_ctx)
        {
            using (var _ctxTransaction = _ctx.Database.BeginTransaction())
            {
                try
                {
                    var entityUpdate = _ctx.Contacts.FirstOrDefault(x => x.ContactId == id);
                    if (entityUpdate != null)
                    {
                        entityUpdate.FirstName = model.FirstName;
                        entityUpdate.LastName = model.LastName;
                        entityUpdate.Phone = model.Phone;
                        entityUpdate.Email = model.Email;

                        await _ctx.SaveChangesAsync();
                    }
                    _ctxTransaction.Commit();
                    message = "Entry Updated";
                }
                catch (Exception e)
                {
                    _ctxTransaction.Rollback(); e.ToString();
                    message = "Entry Update Failed!!";
                }

                result = new
                {
                    message
                };
            }
        }
        return result;
    }

    // DELETE api/Contact/DeleteContactByID/5
    [HttpDelete, Route("DeleteContactByID/{id}")]
    public async Task<object> DeleteContactByID(int id)
    {
        object result = null; string message = "";
        using (_ctx)
        {
            using (var _ctxTransaction = _ctx.Database.BeginTransaction())
            {
                try
                {
                    var idToRemove = _ctx.Contacts.SingleOrDefault(x => x.ContactId == id);
                    if (idToRemove != null)
                    {
                        _ctx.Contacts.Remove(idToRemove);
                        await _ctx.SaveChangesAsync();
                    }
                    _ctxTransaction.Commit();
                    message = "Deleted Successfully";
                }
                catch (Exception e)
                {
                    _ctxTransaction.Rollback(); e.ToString();
                    message = "Error on Deleting!!";
                }

                result = new
                {
                    message
                };
            }
        }
        return result;
    }
}

我们可以使用属性“DisableCors”禁用 CORS。 在此控制器中,我们已将其应用于“PUT”方法以禁用 CORS。

发布到 IIS

我们需要为 ASP.NET Core 应用程序准备服务器以进行托管。 获取有关 发布 .NET Core 应用程序 的更多详细信息。 我们使用了 localhost 并分配了端口 8081 以通过我们的共享应用程序进行访问。 https://:8081

cors27

让我们使用 https://:8081 url 浏览我们的应用程序,正如您所看到的,我们的 API 正在使用 JSON 数据响应。

core_23

现在,是时候访问共享资源了。 我已将 现有示例应用程序添加到此解决方案。 以下是我所做的简单更改,以通过来自不同源的 API 访问资源。

共享资源

 public _saveUrl: string = 'https://:8081/api/Contact/PostContact';
 public _updateUrl: string = 'https://:8081/api/Contact/PutContact';
 public _getUrl: string = 'https://:8081/api/Contact/GetContact';
 public _getByIdUrl: string = 'https://:8081/api/Contact/GetContactByID';
 public _deleteByIdUrl: string = 'https://:8081/api/Contact/DeleteContactByID';

在这里,我们尝试通过 https://:8081 访问资源,但发生服务器错误,如下所示。

core_25

启用 CORS 后,我们成功地通过 Web API 访问了共享资源。

cors28

输出

core_24

源代码:我已将完整的源代码上传到 download/clone @github,希望这对您有所帮助。 :)

© . All rights reserved.