当 Identity Razor 页面按预期工作时,使用 MVC 页面获得 401 Unauthorized
Getting 401 Unauthorized with MVC Pages while Identity Razor pages work as expected
背景
我正在进行 POC 以了解 Angular、Razor 和 MVC 页面是否可以在 Web 应用程序中无缝工作。我从名为“ASP.NET Core with Angular”的 Visual Studio 模板开始。我选择了“个人帐户”以包含默认身份验证功能。这会创建一个带有安全网络 API 端点 (WeatherForecast) 的 Angular 应用程序,并提供基本的用户注册、登录、注销、用户个人资料页面等内置功能。到目前为止,当我尝试从受保护的 API (WeatherForecast) 获取数据 我被重定向到 Identiy/Account/Login razor 页面,在那里我可以登录,然后被重定向回 Angular 我可以看到数据已返回并且网格人口稠密。至此一切正常。
问题
我添加了一个带有基本“Hello World”HTML 视图的 DemoController class。当我尝试使用 /demo 访问这个新页面时,它按预期工作。但是,当我将 [Authorize]
属性应用于控制器时,我得到 401 Unauthorized。我在服务器端检查 User.IsAuthenticated
属性 设置为 false
尽管之前已成功登录。现在有趣的观察是用户个人资料页面(受保护并且只有在有活动登录时才能工作)工作正常。
请注意,来自 Angular 的所有 API 调用问题都使用 JWT 不记名令牌并且工作正常。当我尝试访问用户个人资料页面时,它不使用 JWT,而是使用 cookie 进行身份验证。对 /demo 页面的 GET 请求在 headers 中也有所有这些 cookie,但仍然遇到 401.
我花了很多时间浏览文章,搜索网络但没有成功。我们发现的最后一件事是:
但这也无济于事。
该项目是使用Visual Studio 2022、.net core 6.0 创建的。这是供您参考的 Program.cs 文件:
using CoreAngular.Data;
using CoreAngular.Models;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
builder.Services.AddAuthentication()
.AddIdentityServerJwt();
builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseMigrationsEndPoint();
}
else
{
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseIdentityServer();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller}/{action=Index}/{id?}");
app.MapRazorPages();
app.MapFallbackToFile("index.html"); ;
app.Run();
这里已经回答了:
事实证明,使用 IdentityServer 扩展方法添加了一个策略方案,使得只有 /Identity 页面具有 cookie 身份验证。其余默认为JWT。
我们可以通过添加我们自己的策略来自定义它,如下所示:
builder.Services.AddAuthentication()
.AddIdentityServerJwt()
.AddPolicyScheme("ApplicationDefinedAuthentication", null, options =>
{
options.ForwardDefaultSelector = (context) =>
{
if (context.Request.Path.StartsWithSegments(new PathString("/Identity"), StringComparison.OrdinalIgnoreCase) ||
context.Request.Path.StartsWithSegments(new PathString("/demo"), StringComparison.OrdinalIgnoreCase))
return IdentityConstants.ApplicationScheme;
else
return IdentityServerJwtConstants.IdentityServerJwtBearerScheme;
};
});
// Use own policy scheme instead of default policy scheme that was set in method AddIdentityServerJwt
builder.Services.Configure<AuthenticationOptions>(options => options.DefaultScheme = "ApplicationDefinedAuthentication");
背景
我正在进行 POC 以了解 Angular、Razor 和 MVC 页面是否可以在 Web 应用程序中无缝工作。我从名为“ASP.NET Core with Angular”的 Visual Studio 模板开始。我选择了“个人帐户”以包含默认身份验证功能。这会创建一个带有安全网络 API 端点 (WeatherForecast) 的 Angular 应用程序,并提供基本的用户注册、登录、注销、用户个人资料页面等内置功能。到目前为止,当我尝试从受保护的 API (WeatherForecast) 获取数据 我被重定向到 Identiy/Account/Login razor 页面,在那里我可以登录,然后被重定向回 Angular 我可以看到数据已返回并且网格人口稠密。至此一切正常。
问题
我添加了一个带有基本“Hello World”HTML 视图的 DemoController class。当我尝试使用 /demo 访问这个新页面时,它按预期工作。但是,当我将 [Authorize]
属性应用于控制器时,我得到 401 Unauthorized。我在服务器端检查 User.IsAuthenticated
属性 设置为 false
尽管之前已成功登录。现在有趣的观察是用户个人资料页面(受保护并且只有在有活动登录时才能工作)工作正常。
请注意,来自 Angular 的所有 API 调用问题都使用 JWT 不记名令牌并且工作正常。当我尝试访问用户个人资料页面时,它不使用 JWT,而是使用 cookie 进行身份验证。对 /demo 页面的 GET 请求在 headers 中也有所有这些 cookie,但仍然遇到 401.
我花了很多时间浏览文章,搜索网络但没有成功。我们发现的最后一件事是:
该项目是使用Visual Studio 2022、.net core 6.0 创建的。这是供您参考的 Program.cs 文件:
using CoreAngular.Data;
using CoreAngular.Models;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
builder.Services.AddAuthentication()
.AddIdentityServerJwt();
builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseMigrationsEndPoint();
}
else
{
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseIdentityServer();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller}/{action=Index}/{id?}");
app.MapRazorPages();
app.MapFallbackToFile("index.html"); ;
app.Run();
这里已经回答了:
事实证明,使用 IdentityServer 扩展方法添加了一个策略方案,使得只有 /Identity 页面具有 cookie 身份验证。其余默认为JWT。
我们可以通过添加我们自己的策略来自定义它,如下所示:
builder.Services.AddAuthentication()
.AddIdentityServerJwt()
.AddPolicyScheme("ApplicationDefinedAuthentication", null, options =>
{
options.ForwardDefaultSelector = (context) =>
{
if (context.Request.Path.StartsWithSegments(new PathString("/Identity"), StringComparison.OrdinalIgnoreCase) ||
context.Request.Path.StartsWithSegments(new PathString("/demo"), StringComparison.OrdinalIgnoreCase))
return IdentityConstants.ApplicationScheme;
else
return IdentityServerJwtConstants.IdentityServerJwtBearerScheme;
};
});
// Use own policy scheme instead of default policy scheme that was set in method AddIdentityServerJwt
builder.Services.Configure<AuthenticationOptions>(options => options.DefaultScheme = "ApplicationDefinedAuthentication");