如何在ASP NET Core中实现CORS跨域

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在ASP NET Core中实现CORS跨域相关的知识,希望对你有一定的参考价值。

1、CORS的原理:CORS定义一种跨域访问的机制,可以让AJAX实现跨域访问。CORS 允许一个域上的网络应用向另一个域提交跨域 AJAX 请求。实现此功能非常简单,只需由服务器发送一个响应标头即可。
2、tomcat如何配置cors的跨域请求: 
在tomcat中,有一个和cors相关的拦截器:CORS Filter
该过滤器可以通过添加必需的访问控制请求头Access-Control-*对象来进行跨域。同时还可以对一些请求进行拦截。如果请求是无效的,或者是不被允许的,该请求被拒绝或者禁止。 
其在web.xml文件中的基本配置如下:
<filter>
        <filter-name>CorsFilter</filter-name>
        <filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
        <init-param>
            <param-name>cors.allowed.origins</param-name>
            <param-value>
                ,
                
            </param-value>
        </init-param>
        <init-param>
            <param-name>cors.allowed.methods</param-name>
            <param-value>
                GET,POST,HEAD,OPTIONS,PUT
            </param-value>
        </init-param>
        <init-param>
            <param-name>cors.allowed.headers</param-name>
            <param-value>
                Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers,Access-Control-Allow-Origin
            </param-value>
        </init-param>
        <init-param>
            <param-name>cors.exposed.headers</param-name>
            <param-value>
                Access-Control-Allow-Origin,Access-Control-Allow-Credentials
            </param-value>
        </init-param>
        <init-param>
            <param-name>cors.support.credentials</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>cors.preflight.maxage</param-name>
            <param-value>10</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>CorsFilter</filter-name>
        <url-pattern>/wxrefund/*</url-pattern>
    </filter-mapping>


3、cors.allowed.origins:允许访问资源的源列表。*表示任何来源都可以访问该资源。否则,只有配置的白名单的来源可以访问该资源,其中白名单用逗号隔开,如,。
4、cors.allowed.methods:允许访问的http请求方法,如GET,POST,HEAD,OPTIONS,PUT等,方法名用逗号隔开。
5、cors.allowed.headers:在实际请求时可使用的请求头列表,用逗号隔开。如Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers,Access-Control-Allow-Origin。这些头也将返回作为访问控制的一部分。

参考技术A <step1:ConfigureService中策略的注册代码>
public void ConfigureServices(IServiceCollection services)

services.Configure<CookiePolicyOptions>(options =>

// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
);

//注册跨域请求服务
services.AddCors(options =>

//注册一个名字为“DefaultPolicy”新策略
options.AddPolicy("DefaultPolicy", builder =>

builder.WithOrigins("http://localhost:1001", "http://localhost:1002") //多个地址通过"逗号"隔开
.WithMethods("GET","PUT")
.WithHeaders(Microsoft.Net.Http.Headers.HeaderNames.ContentType, "Authorization")
.AllowCredentials();

);

);
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

[注]补充:在core 2.x版本,AllowAnyOrigin()和AllowCredentials()可以共存,在3.x版本,不能共存,不能共存时需要指定具体的域名。 <step2:Configure全局拦截代码 或者 作用于Action的代码 >
public void Configure(IApplicationBuilder app, IHostingEnvironment env)

if (env.IsDevelopment())

app.UseDeveloperExceptionPage();

else

app.UseExceptionHandler("/Home/Error");

app.UseStaticFiles();
app.UseCookiePolicy();

//全局配置跨域(一定要配置在 app.UseMvc前)
//2. 命名策略
app.UseCors("DefaultPolicy");

app.UseMvc(routes =>

routes.MapRoute(
name: "default",
template: "controller=Home/action=Index/id?");
);

[单个controller/action上指定]
/// <summary>
/// 命名策略
/// </summary>
/// <returns></returns>
[EnableCors("DefaultPolicy")]
[HttpPost]
public string Test()

return "来自config.net.cn上的跨域问题解决办法分享";

如何在ASP.NET Core中实现一个基础的身份认证

注:本文提到的代码示例下载地址> How to achieve a basic authorization in ASP.NET Core

如何在ASP.NET Core中实现一个基础的身份认证

ASP.NET终于可以跨平台了,但是不是我们常用的ASP.NET, 而是叫一个ASP.NET Core的新平台,他可以跨Windows, Linux, OS X等平台来部署你的web应用程序,你可以理解为,这个框架就是ASP.NET的下一个版本,相对于传统ASP.NET程序,它还是有一些不同的地方的,比如很多类库在这两个平台之间是不通用的。

 

今天首先我们在ASP.NET Core中来实现一个基础的身份认证,既登陆功能。

 

前期准备:

1.推荐使用 VS 2015 Update3 作为你的IDE,下载地址:www.visualstudio.com

2.你需要安装.NET Core的运行环境以及开发工具,这里提供VS版:www.microsoft.com/net/core

 

创建项目:

在VS中新建项目,项目类型选择ASP.NET Core Web Application (.NET Core), 输入项目名称为TestBasicAuthor。

技术分享

接下来选择 Web Application, 右侧身份认证选择:No Authentication

技术分享

 

打开Startup.cs

在ConfigureServices方法中加入如下代码:

services.AddAuthorization(); 

在Configure方法中加入如下代码:

技术分享
app.UseCookieAuthentication(new CookieAuthenticationOptions 
{ 
    AuthenticationScheme = "Cookie", 
    LoginPath = new PathString("/Account/Login"), 
    AccessDeniedPath = new PathString("/Account/Forbidden"), 
    AutomaticAuthenticate = true, 
    AutomaticChallenge = true 
}); 
技术分享

完整的代码应该是这样:

技术分享
public void ConfigureServices(IServiceCollection services) 
{ 
    services.AddMvc(); 
 
    services.AddAuthorization(); 
} 
 
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) 
{ 
    app.UseCookieAuthentication(new CookieAuthenticationOptions 
    { 
        AuthenticationScheme = "Cookie", 
        LoginPath = new PathString("/Account/Login"), 
        AccessDeniedPath = new PathString("/Account/Forbidden"), 
        AutomaticAuthenticate = true, 
        AutomaticChallenge = true 
    }); 
 
    app.UseMvc(routes => 
    { 
        routes.MapRoute( 
             name: "default", 
             template: "{controller=Home}/{action=Index}/{id?}"); 
    }); 
}
技术分享

你或许会发现贴进去的代码是报错的,这是因为还没有引入对应的包,进入报错的这一行,点击灯泡,加载对应的包就可以了。

技术分享

在项目下创建一个文件夹命名为Model,并向里面添加一个类User.cs

代码应该是这样

public class User
{
    public string UserName { get; set; }
    public string Password { get; set; }
}

 

创建一个控制器,取名为:AccountController.cs

在类中贴入如下代码:

技术分享
[HttpGet] 
public IActionResult Login() 
{ 
    return View(); 
} 
 
[HttpPost] 
public async Task<IActionResult> Login(User userFromFore) 
{ 
    var userFromStorage = TestUserStorage.UserList 
        .FirstOrDefault(m => m.UserName == userFromFore.UserName && m.Password == userFromFore.Password); 
 
    if (userFromStorage != null) 
    { 
        //you can add all of ClaimTypes in this collection 
        var claims = new List<Claim>() 
        { 
            new Claim(ClaimTypes.Name,userFromStorage.UserName) 
            //,new Claim(ClaimTypes.Email,"[email protected]")  
        }; 
 
        //init the identity instances 
        var userPrincipal = new ClaimsPrincipal(new ClaimsIdentity(claims, "SuperSecureLogin")); 
 
        //signin 
        await HttpContext.Authentication.SignInAsync("Cookie", userPrincipal, new AuthenticationProperties 
        { 
            ExpiresUtc = DateTime.UtcNow.AddMinutes(20), 
            IsPersistent = false, 
            AllowRefresh = false 
        }); 
 
        return RedirectToAction("Index", "Home"); 
    } 
    else 
    { 
        ViewBag.ErrMsg = "UserName or Password is invalid"; 
 
        return View(); 
    } 
} 
 
public async Task<IActionResult> Logout() 
{ 
    await HttpContext.Authentication.SignOutAsync("Cookie"); 
 
    return RedirectToAction("Index", "Home"); 
} 
技术分享

相同的文件里让我们来添加一个模拟用户存储的类

技术分享
//for simple, I‘m not using the database to store the user data, just using a static class to replace it.
public static class TestUserStorage
{
    public static List<User> UserList { get; set; } = new List<User>() {
        new User { UserName = "User1",Password = "112233"}
    };
}
技术分享

接下来修复好各种引用错误。

完整的代码应该是这样

技术分享
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using TestBasicAuthor.Model;
using System.Security.Claims;
using Microsoft.AspNetCore.Http.Authentication;

// For more information on enabling MVC for empty projects, visit http://go.microsoft.com/fwlink/?LinkID=397860

namespace TestBasicAuthor.Controllers
{
    public class AccountController : Controller
    {
        [HttpGet]
        public IActionResult Login()
        {
            return View();
        }

        [HttpPost]
        public async Task<IActionResult> Login(User userFromFore)
        {
            var userFromStorage = TestUserStorage.UserList
                .FirstOrDefault(m => m.UserName == userFromFore.UserName && m.Password == userFromFore.Password);

            if (userFromStorage != null)
            {
                //you can add all of ClaimTypes in this collection 
                var claims = new List<Claim>()
                {
                    new Claim(ClaimTypes.Name,userFromStorage.UserName) 
                    //,new Claim(ClaimTypes.Email,"[email protected]")  
                };

                //init the identity instances 
                var userPrincipal = new ClaimsPrincipal(new ClaimsIdentity(claims, "SuperSecureLogin"));

                //signin 
                await HttpContext.Authentication.SignInAsync("Cookie", userPrincipal, new AuthenticationProperties
                {
                    ExpiresUtc = DateTime.UtcNow.AddMinutes(20),
                    IsPersistent = false,
                    AllowRefresh = false
                });

                return RedirectToAction("Index", "Home");
            }
            else
            {
                ViewBag.ErrMsg = "UserName or Password is invalid";

                return View();
            }
        }

        public async Task<IActionResult> Logout()
        {
            await HttpContext.Authentication.SignOutAsync("Cookie");

            return RedirectToAction("Index", "Home");
        }
    }

    //for simple, I‘m not using the database to store the user data, just using a static class to replace it.
    public static class TestUserStorage
    {
        public static List<User> UserList { get; set; } = new List<User>() {
        new User { UserName = "User1",Password = "112233"}
    };
    }
}
技术分享

在Views文件夹中创建一个Account文件夹,在Account文件夹中创建一个名位index.cshtml的View文件。

贴入如下代码:

技术分享
@model TestBasicAuthor.Model.User


<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
</head>
<body>
    @using (Html.BeginForm())
    {
        <table>
            <tr>
                <td></td>
                <td>@ViewBag.ErrMsg</td>
            </tr>
            <tr>
                <td>UserName</td>
                <td>@Html.TextBoxFor(m => m.UserName)</td>
            </tr>
            <tr>
                <td>Password</td>
                <td>@Html.PasswordFor(m => m.Password)</td>
            </tr>
            <tr>
                <td></td>
                <td><button>Login</button></td>
            </tr>
        </table>
    }
</body>
</html>
技术分享

打开HomeController.cs

添加一个Action, AuthPage.

技术分享
[Authorize]
[HttpGet]
public IActionResult AuthPage()
{
    return View();
}
技术分享

在Views/Home下添加一个视图,名为AuthPage.cshtml

技术分享
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
</head>
<body>
    <h1>Auth page</h1>

    <p>if you are not authorized, you can‘t visit this page.</p>
</body>
</html>
技术分享

到此,一个基础的身份认证就完成了,核心登陆方法如下:

技术分享
await HttpContext.Authentication.SignInAsync("Cookie", userPrincipal, new AuthenticationProperties
{
    ExpiresUtc = DateTime.UtcNow.AddMinutes(20),
    IsPersistent = false,
    AllowRefresh = false
});
技术分享

启用验证如下:

技术分享
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    app.UseCookieAuthentication(new CookieAuthenticationOptions
    {
        AuthenticationScheme = "Cookie",
        LoginPath = new PathString("/Account/Login"),
        AccessDeniedPath = new PathString("/Account/Forbidden"),
        AutomaticAuthenticate = true,
        AutomaticChallenge = true
    });
}
技术分享

在某个Controller或Action添加[Author],即可配置位需要登陆验证的页面。

 

最后:如何运行这个Sample以及下载完整的代码请访问:How to achieve a basic authorization in ASP.NET Core

以上是关于如何在ASP NET Core中实现CORS跨域的主要内容,如果未能解决你的问题,请参考以下文章

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

无法在 ASP.NET Core 1.0 中启用跨域请求 (CORS)

asp.net core 系列之允许跨域访问2之测试跨域(Enable Cross-Origin Requests:CORS)

asp.net core 2.1 跨域策略。添加为 CORS 时,只有单个 url 有效

如何在ASP.NET Core中实现一个基础的身份认证

如何在 ASP.NET Core 中实现自定义模型验证?