JwtBearerAuthentication does not set the HttpContext User



我很难在.NetCoreWebneneneba API中找到有关此主题的相关信息:JwtBearerAuthentication。该令牌是由IdentityServer发布并通过前端客户端应用程序发送的OIDC id令牌。令牌被正确接收和验证,从而生成一个具有15个声明的经过身份验证的ClaimsPrincipal,但当请求到达应用程序时,该主体不存在于HttpContext中。存在未经身份验证的匿名用户,而不是验证令牌时出现的用户。

这个api是由其作者(而不是我(设计的,用于使用OIDC cookie身份验证,但我正在尝试将其转换为使用JWT承载身份验证。

据我所知,我正在根据我能找到的所有例子正确地做每件事,我没有想法。感谢您的帮助。

我已经在下面发布了整个Startup.cs文件,对所有的代码感到抱歉,但你应该能够看到所有相关的东西。。。

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IdentityModel.Tokens.Jwt;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using Autofac;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Autofac.Configuration;
using Autofac.Extensions.DependencyInjection;
using CAS.Authorization.Api.Configuration;
using CAS.Authorization.Api.Defaults.Configuration;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Swashbuckle.AspNetCore.Swagger;
namespace CAS.Authorization.Api
{
[ExcludeFromCodeCoverage]
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public IServiceProvider 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.AddAuthentication(options =>
{
//options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
//options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
// options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
//.AddCookie()
.AddJwtBearer(options =>
{
options.Authority = "http://localhost:40800";
options.RequireHttpsMetadata = false;
options.SaveToken = true;
options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters()
{
ValidateIssuer = false,
ValidIssuer = "http://localhost:40800",
ValidateAudience = false,
ValidAudience = "http://localhost:22426"
};
options.Events = new JwtBearerEvents()
{
OnTokenValidated = async context =>
{
//This does not work, however the context.Principal IS authenticated
//and DOES have claims (15 of them).
context.HttpContext.User = context.Principal;
}
};
});
//.AddOpenIdConnect(options =>
//{
//    options.SignInScheme = "Cookies";
//    options.Authority = "http://localhost:40800";
//    options.ClientId = "defaultClientId";
//    options.SignInScheme = "Cookies";
//    options.RequireHttpsMetadata = false;
//    options.ResponseType = "code";
//    options.Scope.Add("profile");
//    options.GetClaimsFromUserInfoEndpoint = true;
//    options.SaveTokens = true;
//    options.ClaimActions.MapAllExcept("iss", "nbf", "exp", "aud", "nonce", "iat", "c_hash");
//});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddHttpContextAccessor();
services.AddAuthorization(PolicyConfiguration.SetupPolicies);
services.AddSingleton<IAuthorizationHandler, AccessPolicyHandler>();
services.AddTransient<IActionContextAccessor, ActionContextAccessor>();
//Api Versioning
//services.AddApiVersioning(o =>
//{
//    o.ReportApiVersions = true;
//    o.ApiVersionReader = new UrlSegmentApiVersionReader();
//});
services.Configure<BusSettings>(Configuration.GetSection("BusSettings"));
//Swagger
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Info { Title = "CAS Authorization API", Version = "v1" });

//Locate the XML file being generated by ASP.NET...
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.XML";
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
//... and tell Swagger to use those XML comments.
c.IncludeXmlComments(xmlPath);
});
// Add Autofac
// ConfigurationModule accepts JSON configuration for other modules/components to register,
// instead of having references here to those modules, directly.
// If we ever want to remove those direct references, this should still work.
// config.AddJsonFile comes from Microsoft.Extensions.Configuration.Json
var config = new ConfigurationBuilder();
config.AddJsonFile("modules.json");
// Register the ConfigurationModule with Autofac.
var module = new ConfigurationModule(config.Build());
var builder = new ContainerBuilder();
builder.RegisterAssemblyModules();
builder.RegisterModule(module);
builder.Populate(services);
var container = builder.Build();
return new AutofacServiceProvider(container);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();

}
app.UseCookiePolicy();
app.UseAuthentication();
app.UseHttpsRedirection();
app.UseMvc();
//Swagger UI
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "CAS Authorization API - v1");
c.RoutePrefix = string.Empty;
});
}
}
}

编辑以添加尝试访问用户的示例,在下面的GetClaimsByOrganization方法中:

public class UserIdentityService : IUserIdentityService
{
private HttpContext _context;
public UserIdentityService(IHttpContextAccessor contextAccessor)
{
_context = contextAccessor?.HttpContext ?? throw new ArgumentNullException();
}
public string UserName => _context.User.FindFirst(ClaimTypes.Name)?.Value;
public Guid Sub => Guid.Parse(_context.User.FindFirst(ClaimTypes.NameIdentifier)?.Value);
public Claim[] GetPermissionClaims(string permissionName, string resourceName)
{
if (string.IsNullOrWhiteSpace(permissionName)) throw new ArgumentException("Invalid permission name");
if (string.IsNullOrWhiteSpace(resourceName)) throw new ArgumentException("Invalid resource name");
return _context.User?.Claims?.Where(c => c.Type.Contains("ORG:") && c.Value == resourceName.ToUpper() + permissionName.ToUpper()).ToArray();
}
public Claim[] GetClaimsByOrganization(string orgName)
{
if (string.IsNullOrWhiteSpace(orgName)) throw new ArgumentException("Invalid organization name");
return _context.User?.Claims?.Where(c => c.Type == "ORG:" + orgName.ToUpper()).ToArray();
}
}

问题已解决。这是对Identity Server、客户端应用程序和API的概念验证,所有这些都在Visual Studio调试中运行,并使用尽可能多的默认设置。我用http访问API。当我在它的https端口上点击它时,它工作了。显然,身份验证中间件只在请求使用https时设置用户。

最新更新