You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 7应用部署Azure时IdentityServer密钥配置错误排查与修复

.NET 7 + Angular 16 Azure部署问题修复指南

问题背景

本地开发环境运行正常,但部署到Azure后API与前端无法协同,API返回HTML而非JSON,日志报错:

No signing credential is configured by the 'IdentityServer:Key' configuration section.

当前配置与代码

appsettings.json

"IdentityServer": {
    "Clients": {
      "MyApp": {
        "Profile": "IdentityServerSPA"
      }
    }
}

Program.cs

using MyApp.DB;
using MyApp.DB.DataAccess;
using MyApp.DB.Entities;
using MyApp.DB.Reps;
using MyApp.DB.Reps.Interfaces;
using MyApp.Utilities.Configurations;
using MyApp.Utilities.Emails;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.EntityFrameworkCore;
using System.Text.Json.Serialization;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") 
                       ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");

builder.Services.AddDbContext<AppDbCtx>(options =>
    options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();

var passwordComplexity = builder.Configuration.GetSection("PasswordComplexity").Get<PasswordComplexity>();
builder.Services.AddIdentity<ApplicationUser, IdentityRole>(options =>
    {
        options.SignIn.RequireConfirmedAccount = true;
        options.Password.RequireDigit = passwordComplexity?.RequireDigit ?? true;
        options.Password.RequireLowercase = passwordComplexity?.RequireLowercase ?? true;
        options.Password.RequireNonAlphanumeric = passwordComplexity?.RequireNonAlphanumeric ?? true;
        options.Password.RequireUppercase = passwordComplexity?.RequireUppercase ?? true;
        options.Password.RequiredLength = passwordComplexity?.RequiredLength ?? 6;
        options.Password.RequiredUniqueChars = passwordComplexity?.RequiredUniqueChars ?? 1;
    }).AddDefaultTokenProviders()
    .AddEntityFrameworkStores<AppDbCtx>();

builder.Services.AddScoped<IDbInitializer, DbInitializer>();
builder.Services.AddSingleton<IEmailSender, EmailSender>();
builder.Services.AddScoped<IUnitOfWork, UnitOfWork>();

builder.Services.AddIdentityServer()
    .AddApiAuthorization<ApplicationUser, AppDbCtx>();

builder.Services.AddAuthentication()
    .AddIdentityServerJwt();

builder.Services.AddHttpContextAccessor();

builder.Services.AddControllersWithViews()
    .AddJsonOptions(x => x.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles);
builder.Services.AddRazorPages();

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

builder.Services.AddCors(options => options.AddPolicy(name: "FrontEndUI",
    policy =>
    {
        policy.WithOrigins("http://localhost:4200")
            .AllowAnyMethod()
            .AllowAnyHeader();
    }
));

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();

SeedDatabase();

app.UseAuthentication();
app.UseIdentityServer();
app.UseAuthorization();

app.UseSwagger();
app.UseSwaggerUI();

app.UseCors("FrontEndUI");

app.MapControllerRoute(
    name: "default",
    pattern: "{controller}/{action=Index}/{id?}");
app.MapRazorPages();

app.MapFallbackToFile("index.html");

app.Run();

void SeedDatabase()
{
    using (var scope = app.Services.CreateScope())
    {
        var dbInitializer = scope.ServiceProvider.GetRequiredService<IDbInitializer>();
        dbInitializer.Initialize();
    }
}

修复步骤

1. 解决IdentityServer签名凭证缺失问题

本地开发时,IdentityServer会自动生成临时签名密钥,但生产环境(Azure)必须配置持久化的签名凭证,否则服务启动失败,导致API返回错误页面(HTML)。以下两种方案可选:

方案一:使用Azure Key Vault存储密钥(推荐生产环境)

在appsettings.json中添加Key配置:

"IdentityServer": {
  "Key": {
    "Type": "AzureKeyVault",
    "Vault": "你的Azure Key Vault名称",
    "Name": "存储的密钥名称"
  },
  "Clients": {
    "MyApp": {
      "Profile": "IdentityServerSPA"
    }
  }
}

然后在Azure门户中,给你的应用服务分配访问该Key Vault的权限(通过托管标识),确保应用能读取密钥。

方案二:使用RSA密钥(适用于测试/小型应用)

生成RSA密钥对后,将密钥信息添加到配置中(注意:生产环境不建议明文存储,优先用Key Vault):

"IdentityServer": {
  "Key": {
    "Type": "Rsa",
    "Key": "你的RSA私钥内容",
    "PublicKey": "你的RSA公钥内容"
  },
  "Clients": {
    "MyApp": {
      "Profile": "IdentityServerSPA"
    }
  }
}

或者在Program.cs中直接配置证书:

builder.Services.AddIdentityServer()
    .AddApiAuthorization<ApplicationUser, AppDbCtx>()
    .AddSigningCredential(new X509Certificate2("证书文件路径", "证书密码"));

如果使用Azure应用服务的托管证书,可通过环境变量或Azure配置获取证书实例。

2. 修正API返回HTML的问题

解决签名凭证问题后,IdentityServer能正常启动,API会恢复返回JSON。同时需检查:

  • 更新CORS策略:将http://localhost:4200替换为Angular应用的生产域名,例如https://your-angular-app.azurewebsites.net
  • 确认前端API_BASE_URL配置:确保Angular应用请求的是Azure上的API地址,而非本地地址

微软示例配置值说明

针对你提到的示例配置:

"IdentityServer": {
  "Clients": {
    "MySPA": {
      "Profile": "SPA",
      "RedirectUri": "https://www.example.com/authentication/login-callback",
      "LogoutUri": "https://www.example.com/authentication/logout-callback"
    }
  }
}

各字段取值规则:

  • Profile: Angular应用使用IdentityServerSPA(与你当前配置一致)即可,该配置是针对ASP.NET Core Identity集成的SPA优化项;SPA是通用SPA配置,两者均可
  • RedirectUri: 对应Angular应用中认证回调的地址,默认模板路径为/authentication/login-callback,所以完整地址是你的Angular生产域名+该路径,例如https://your-angular-app.azurewebsites.net/authentication/login-callback
  • LogoutUri: 对应Angular应用中登出回调的地址,类似登录回调,例如https://your-angular-app.azurewebsites.net/authentication/logout-callback

这些值必须与Angular应用中的认证配置(如authConfig里的redirectUri和postLogoutRedirectUri)完全一致。


内容的提问来源于stack exchange,提问作者Razvan Zamfir

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 19:34:56