在ASP.NET Core 3.1中如何使用多个身份验证方案?

21

我正在使用ASP.NET Core 3.1和干净的架构设计制作Web应用程序。

我有一些类库,如Infrastructure、Persistence、Domain、Application以及一个名为“Web”的MVC应用程序项目作为我的应用程序的启动点。

在Web层中,我有“Areas”,其中包含一些控制器和返回JSON作为API终点的操作方法,供基于React的应用程序使用。

我还在Web MVC项目中的Controllers文件夹中有一些控制器,它们的操作方法返回HTML视图

我也在我的API终点中使用Identity和JWT,但是:

- 如果我想在我的MVC控制器中使用基于声明(claims-based)的Identity,并且它们的操作结果返回HTML视图怎么办?

- 在ASP.NET Core 3.1中,在这样的应用程序中使用基于声明的Identity的最佳实践是什么?

任何帮助都将不胜感激。

2个回答

28

在进行一些研究后,我在 ASP.NET Core 授权文档中的一篇标题为 "ASP.NET Core 中使用特定方案的授权" 的文章中找到了解决方案。

根据 Microsoft ASP .NET Core 文档中提到的文章,在某些情况下,例如单页应用程序(SPA),常见的是使用多种身份验证方法。例如,应用程序可能使用基于 cookie 的身份验证来登录,并为 JavaScript 请求使用 JWT 令牌身份验证。

当进行身份验证期间配置身份验证服务时,会为身份验证方案命名。例如:

public void ConfigureServices(IServiceCollection services)
{
    // Code omitted for brevity

    services.AddAuthentication()
        .AddCookie(options => {
            options.LoginPath = "/Account/Unauthorized/";
            options.AccessDeniedPath = "/Account/Forbidden/";
        })
        .AddJwtBearer(options => {
            options.Audience = "http://localhost:5001/";
            options.Authority = "http://localhost:5000/";
        });
在前面的代码中,添加了两个身份验证处理程序:一个用于 cookie,一个用于 bearer。
使用 Authorize 属性选择方案。
[Authorize(AuthenticationSchemes = 
    JwtBearerDefaults.AuthenticationScheme)]
public class MixedController : Controller
在前面的代码中,只有使用“Bearer”方案的处理程序运行。任何基于cookie的身份验证均被忽略。
这是解决我的问题的解决方案,我认为与需要此功能的人分享会很好。

14

.Net Core 3.1或.Net 5.0中的多种身份验证方案

Startup.cs文件

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
                    .AddCookie(x =>
                    {
                        x.LoginPath = "/";
                        x.ExpireTimeSpan = TimeSpan.FromMinutes(Configuration.GetValue<int>("CookieExpiry"));
                    })
                    .AddJwtBearer(x =>
                    {
                        x.RequireHttpsMetadata = false;
                        x.SaveToken = true;
                        x.TokenValidationParameters = new TokenValidationParameters
                        {
                            ValidateIssuerSigningKey = true,
                            IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(Configuration.GetValue<string>("JWTSecret"))),
                            ValidateIssuer = false,
                            ValidateAudience = false
                        };
                    });

            services.AddAuthorization(options =>
            {
                var defaultAuthorizationPolicyBuilder = new AuthorizationPolicyBuilder(CookieAuthenticationDefaults.AuthenticationScheme, JwtBearerDefaults.AuthenticationScheme);
                defaultAuthorizationPolicyBuilder = defaultAuthorizationPolicyBuilder.RequireAuthenticatedUser();
                options.DefaultPolicy = defaultAuthorizationPolicyBuilder.Build();
            });

/api/auth/login

public async Task<AuthenticationResult> Login([FromForm] string userName, [FromForm] string password, [FromHeader] string authmode = "")
{
    if (userName != "demo" || password != "demo")
        return new AuthenticationResult { HasError = true, Message = "Either the user name or password is incorrect." };

    var claims = new Claim[]
    {
        new Claim(ClaimTypes.Name, userName)
    };
    

    if(authmode?.ToLower() == "token")
    {
        var tokenHandler = new JwtSecurityTokenHandler();
        var key = Encoding.ASCII.GetBytes(_config.GetValue<string>("JWTSecret"));
        var tokenDescriptor = new SecurityTokenDescriptor
        {
            Subject = new ClaimsIdentity(claims, "JWT"),
            Expires = DateTime.UtcNow.AddMinutes(_config.GetValue<int>("JWTExpiry")),
            SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
        };
        var token = tokenHandler.CreateToken(tokenDescriptor);
        var jwt = tokenHandler.WriteToken(token);
        return new AuthenticationResult { Token = jwt };
    }
    else
    {
        ClaimsPrincipal princ = new ClaimsPrincipal(new ClaimsIdentity(claims, "COOKIE"));
        await HttpContext.SignInAsync(princ);
        return new AuthenticationResult();
    }
}

输出:

在此输入图片描述 在此输入图片描述

在此输入图片描述 在此输入图片描述

这段代码展示了四张图片的链接。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接