使用 IdentityServer 在 .NET API 上找不到控制器路由
Controller routes not being found on .NET API with IdentityServer
我有一个 .NET API 服务,我设置它来处理身份验证和一些用户管理端点。服务配置如下:
public class Program {
public static void Main(string[] args) {
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder => webBuilder.UseStartup<Startup>());
}
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 void ConfigureServices(IServiceCollection services) {
_ = services.AddScoped<IUserRequester, UserRequester>(_ =>
new UserRequester(Configuration.GetSection("AzureTableStore.UserLogin").Get<TableStoreConfiguration>()));
_ = services.AddControllers().AddNewtonsoftJson(options =>
options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver());
X509Certificate2 certData = DownloadCertificate(Configuration.GetSection("APICertificate").Get<Secret>());
IIdentityServerBuilder builder = services.AddIdentityServer().AddSigningCredential(certData);
builder.AddInMemoryClients(Clients.Get());
builder.AddInMemoryIdentityResources(Identities.Get());
builder.AddInMemoryApiResources(Apis.GetResources());
builder.AddInMemoryApiScopes(Apis.GetScopes());
builder.Services.Configure<TableStoreConfiguration>(Configuration.GetSection("AzureTableStore.UserLogin"));
builder.Services.Configure<RedisConfiguration>(Configuration.GetSection("RedisCache"));
builder.Services.AddTransient<IRedisConnection, RedisConnection>();
builder.Services.AddTransient<IUserRequester, UserRequester>();
builder.Services.AddTransient<IProfileService, ProfileService>();
builder.Services.AddTransient<IResourceOwnerPasswordValidator, PasswordValidator>();
builder.Services.AddTransient<IAuthorizationCodeStore, AuthorizationCodeStore>();
builder.Services.AddTransient<IReferenceTokenStore, ReferenceTokenStore>();
builder.Services.AddTransient<IRefreshTokenStore, RefreshTokenStore>();
builder.Services.AddTransient<IUserConsentStore, UserConsentStore>();
services.AddSwaggerGen(c => c.SwaggerDoc("v1", new OpenApiInfo { Title = "Authentication", Version = "v1" }));
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
if (env.IsDevelopment()) {
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Authentication v1"));
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseIdentityServer();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller}/{action=Index}/{id?}"));
}
private static X509Certificate2 DownloadCertificate(Secret secret) {
KeyVaultSecret key = new Provider(secret.KeyVaultName).GetSecretAsync(secret.SecretName).Result;
return new X509Certificate2(Convert.FromBase64String(key.Value), string.Empty, X509KeyStorageFlags.UserKeySet);
}
}
我的 API 控制器看起来像这样(省略函数体):
[Route("users")]
[ApiController]
internal sealed class UserController : ControllerBase {
private Data.IUserRequester Requester { get; }
public UserController(Data.IUserRequester requester) {
Requester = requester ?? throw new ArgumentNullException(nameof(requester));
}
[HttpGet("{email}")]
public async Task<IActionResult> GetUserAsync(string email, CancellationToken token) {
...
}
[HttpPost]
public async Task<IActionResult> AddUserAsync(User input, CancellationToken token) {
...
}
[HttpDelete]
public async Task<IActionResult> DeleteUserAsync(string email, CancellationToken token) {
...
}
}
这在我调用 https://localhost:{PORT}/connect/token
和其他与身份验证相关的端点时有效。我遇到的问题是,当我向 https://localhost:{PORT}/users
发送 POST 请求时,我收到 404 not-found 响应。这告诉我我的服务找不到我的控制器。但是,我在没有 Identity Server 的情况下使用相同的控制器设置的其他服务并且它们工作正常,那么我在这里做错了什么?
也许尝试制作控制器classpublic?密封在这里也没有任何意义。
我有一个 .NET API 服务,我设置它来处理身份验证和一些用户管理端点。服务配置如下:
public class Program {
public static void Main(string[] args) {
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder => webBuilder.UseStartup<Startup>());
}
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 void ConfigureServices(IServiceCollection services) {
_ = services.AddScoped<IUserRequester, UserRequester>(_ =>
new UserRequester(Configuration.GetSection("AzureTableStore.UserLogin").Get<TableStoreConfiguration>()));
_ = services.AddControllers().AddNewtonsoftJson(options =>
options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver());
X509Certificate2 certData = DownloadCertificate(Configuration.GetSection("APICertificate").Get<Secret>());
IIdentityServerBuilder builder = services.AddIdentityServer().AddSigningCredential(certData);
builder.AddInMemoryClients(Clients.Get());
builder.AddInMemoryIdentityResources(Identities.Get());
builder.AddInMemoryApiResources(Apis.GetResources());
builder.AddInMemoryApiScopes(Apis.GetScopes());
builder.Services.Configure<TableStoreConfiguration>(Configuration.GetSection("AzureTableStore.UserLogin"));
builder.Services.Configure<RedisConfiguration>(Configuration.GetSection("RedisCache"));
builder.Services.AddTransient<IRedisConnection, RedisConnection>();
builder.Services.AddTransient<IUserRequester, UserRequester>();
builder.Services.AddTransient<IProfileService, ProfileService>();
builder.Services.AddTransient<IResourceOwnerPasswordValidator, PasswordValidator>();
builder.Services.AddTransient<IAuthorizationCodeStore, AuthorizationCodeStore>();
builder.Services.AddTransient<IReferenceTokenStore, ReferenceTokenStore>();
builder.Services.AddTransient<IRefreshTokenStore, RefreshTokenStore>();
builder.Services.AddTransient<IUserConsentStore, UserConsentStore>();
services.AddSwaggerGen(c => c.SwaggerDoc("v1", new OpenApiInfo { Title = "Authentication", Version = "v1" }));
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
if (env.IsDevelopment()) {
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Authentication v1"));
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseIdentityServer();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller}/{action=Index}/{id?}"));
}
private static X509Certificate2 DownloadCertificate(Secret secret) {
KeyVaultSecret key = new Provider(secret.KeyVaultName).GetSecretAsync(secret.SecretName).Result;
return new X509Certificate2(Convert.FromBase64String(key.Value), string.Empty, X509KeyStorageFlags.UserKeySet);
}
}
我的 API 控制器看起来像这样(省略函数体):
[Route("users")]
[ApiController]
internal sealed class UserController : ControllerBase {
private Data.IUserRequester Requester { get; }
public UserController(Data.IUserRequester requester) {
Requester = requester ?? throw new ArgumentNullException(nameof(requester));
}
[HttpGet("{email}")]
public async Task<IActionResult> GetUserAsync(string email, CancellationToken token) {
...
}
[HttpPost]
public async Task<IActionResult> AddUserAsync(User input, CancellationToken token) {
...
}
[HttpDelete]
public async Task<IActionResult> DeleteUserAsync(string email, CancellationToken token) {
...
}
}
这在我调用 https://localhost:{PORT}/connect/token
和其他与身份验证相关的端点时有效。我遇到的问题是,当我向 https://localhost:{PORT}/users
发送 POST 请求时,我收到 404 not-found 响应。这告诉我我的服务找不到我的控制器。但是,我在没有 Identity Server 的情况下使用相同的控制器设置的其他服务并且它们工作正常,那么我在这里做错了什么?
也许尝试制作控制器classpublic?密封在这里也没有任何意义。