HttpRequestException:响应状态代码不表示成功:401(未授权)
HttpRequestException: Response status code does not indicate success: 401 (Unauthorized)
我是 IdentityServer4 的新手,正在关注这篇文章。
Protecting an API using Client Credentials
我在尝试使用客户端凭据验证 API 时收到以下错误消息。
HttpRequestException:响应状态码不表示成功:401(未授权)。
下面是IdentityServer4的Startup.cs
的代码
public class Startup
{
public IWebHostEnvironment Environment { get; }
public IConfiguration Configuration { get; }
public Startup(IWebHostEnvironment environment, IConfiguration configuration)
{
Environment = environment;
Configuration = configuration;
}
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
var connectionString = Configuration.GetConnectionString("DefaultConnection");
var builder = services.AddIdentityServer(options =>
{
options.EmitStaticAudienceClaim = true;
options.IssuerUri = "https://localhost:5001";
})
.AddTestUsers(TestUsers.Users)
.AddConfigurationStore(options =>
{
options.ConfigureDbContext = b => b.UseSqlServer(
connectionString,
sql => sql.MigrationsAssembly(migrationsAssembly));
})
.AddOperationalStore(options =>
{
options.ConfigureDbContext = b => b.UseSqlServer(
connectionString,
sql => sql.MigrationsAssembly(migrationsAssembly));
});
builder.AddDeveloperSigningCredential();
}
public void Configure(IApplicationBuilder app)
{
if (Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseStaticFiles();
app.UseRouting();
app.UseIdentityServer();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
});
if (Configuration["seed"] != null)
{
Logger.Information("Seeding data...");
Data.SeedData.Seed(app);
}
}
}
这是 IdentityServer4 的 Config.cs
的代码
public static class Config
{
public static IEnumerable<IdentityResource> IdentityResources =>
new List<IdentityResource>
{
new IdentityResources.OpenId(),
new IdentityResources.Profile(),
};
public static IEnumerable<ApiScope> ApiScopes =>
new List<ApiScope>
{
new ApiScope("InventoryApi", "Inventory Management")
};
public static IEnumerable<Client> Clients =>
new List<Client>
{
new Client
{
ClientId = "CorpLense.Inventory.WebClient",
ClientSecrets = { new Secret("4678a2df-9a5d-486d-ba66-d97ae503c1a6".Sha256()) },
AllowedGrantTypes = GrantTypes.Code,
RedirectUris = { "https://localhost:44302/signin-oidc" },// port here should match with sslPort mentioned in launchSetting.json from CorpLense.Inventory.WebClient
PostLogoutRedirectUris = { "https://localhost:44302/signout-callback-oidc" },// port here should match with sslPort mentioned in launchSetting.json from CorpLense.Inventory.WebClient
AllowOfflineAccess = true,
AllowedScopes = new List<string>
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"InventoryApi" // give this client access to this scope
}
}
};
}
这里是WebApi的Startup.cs
的代码
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
#region Authentication
services.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", options =>
{
options.Authority = Configuration["IdentityServerUri"];
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = false
};
});
#endregion
#region Authorization
services.AddAuthorization(options =>
{
options.AddPolicy("ApiScope", policy =>
{
policy.RequireAuthenticatedUser();
policy.RequireClaim("scope", "InventoryApi");
});
});
#endregion
// register controller services
services.AddControllers()
.AddFluentValidation(fv =>
{
fv.RegisterValidatorsFromAssemblyContaining<Startup>();
fv.DisableDataAnnotationsValidation = true;
});
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "CorpLense.Inventory.WebApi", Version = "v1" });
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
In = ParameterLocation.Header,
Description = "Please Enter Authentication Token",
Name = "InventoryApi",
Type = SecuritySchemeType.ApiKey
});
});
services.AddDbContext<ApplicationContext>(options => options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection"),
b => b.MigrationsAssembly("CorpLense.Inventory.WebApi")));
#region Repositories
services.AddTransient(typeof(IGenericRepository<>), typeof(GenericRepository<>));
services.AddTransient<ISiteRepository, SiteRepository>();
services.AddTransient<IWarehouseRepository, WarehouseRepository>();
#endregion
services.AddTransient<IUnitOfWork, UnitOfWork>();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "CorpLense.Inventory.WebApi v1"));
}
else
{
// register global exception handling service
app.UseExceptionHandler("/Error");
// register global status code error page handling service
app.UseStatusCodePagesWithReExecute("/Error/{0}");
}
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
这里是 WebClient 的代码 Startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie(options =>
{
options.Cookie.Name = "CorpLense.Inventory.WebClient";
})
.AddOpenIdConnect("oidc", options =>
{
options.Authority = Configuration["IdentityServerUri"];
options.ClientId = "CorpLense.Inventory.WebClient";
options.ClientSecret = "4678a2df-9a5d-486d-ba66-d97ae503c1a6";
options.ResponseType = "code";
options.SaveTokens = true;
// ask for required resources
options.Scope.Clear();
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("InventoryApi");
options.Scope.Add("offline_access");
});
services.AddControllersWithViews();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}
这里是 WebClient 主控制器的 Index 方法,它给我错误。
public async Task<IActionResult> Index()
{
// request token
var accessToken = await HttpContext.GetTokenAsync("Cookies","access_token");
// create client
var client = new HttpClient();
// set client's bearer token
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
// request content
var content = await client.GetStringAsync("https://localhost:44301/Sites/GetAllSites");
ViewBag.Json = JArray.Parse(content).ToString(); // PREREQ: Install-Package Newtonsoft.Json
return View();
}
这是出错的代码行。
var content = await client.GetStringAsync("https://localhost:44301/Sites/GetAllSites");
在我的应用程序中,我使用此代码访问令牌:
string idToken = HttpContext.GetTokenAsync("id_token").Result ?? "";
string accessToken = HttpContext.GetTokenAsync("access_token").Result ?? "";
如果没有访问令牌,字符串将为空。
你也可以用属性修饰方法,这样如果用户没有正确认证和授权你甚至不能访问它:
[Authorize]
public async Task<IActionResult> Index()
{
}
我是 IdentityServer4 的新手,正在关注这篇文章。 Protecting an API using Client Credentials
我在尝试使用客户端凭据验证 API 时收到以下错误消息。
HttpRequestException:响应状态码不表示成功:401(未授权)。
下面是IdentityServer4的Startup.cs
的代码public class Startup
{
public IWebHostEnvironment Environment { get; }
public IConfiguration Configuration { get; }
public Startup(IWebHostEnvironment environment, IConfiguration configuration)
{
Environment = environment;
Configuration = configuration;
}
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
var connectionString = Configuration.GetConnectionString("DefaultConnection");
var builder = services.AddIdentityServer(options =>
{
options.EmitStaticAudienceClaim = true;
options.IssuerUri = "https://localhost:5001";
})
.AddTestUsers(TestUsers.Users)
.AddConfigurationStore(options =>
{
options.ConfigureDbContext = b => b.UseSqlServer(
connectionString,
sql => sql.MigrationsAssembly(migrationsAssembly));
})
.AddOperationalStore(options =>
{
options.ConfigureDbContext = b => b.UseSqlServer(
connectionString,
sql => sql.MigrationsAssembly(migrationsAssembly));
});
builder.AddDeveloperSigningCredential();
}
public void Configure(IApplicationBuilder app)
{
if (Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseStaticFiles();
app.UseRouting();
app.UseIdentityServer();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
});
if (Configuration["seed"] != null)
{
Logger.Information("Seeding data...");
Data.SeedData.Seed(app);
}
}
}
这是 IdentityServer4 的 Config.cs
的代码public static class Config
{
public static IEnumerable<IdentityResource> IdentityResources =>
new List<IdentityResource>
{
new IdentityResources.OpenId(),
new IdentityResources.Profile(),
};
public static IEnumerable<ApiScope> ApiScopes =>
new List<ApiScope>
{
new ApiScope("InventoryApi", "Inventory Management")
};
public static IEnumerable<Client> Clients =>
new List<Client>
{
new Client
{
ClientId = "CorpLense.Inventory.WebClient",
ClientSecrets = { new Secret("4678a2df-9a5d-486d-ba66-d97ae503c1a6".Sha256()) },
AllowedGrantTypes = GrantTypes.Code,
RedirectUris = { "https://localhost:44302/signin-oidc" },// port here should match with sslPort mentioned in launchSetting.json from CorpLense.Inventory.WebClient
PostLogoutRedirectUris = { "https://localhost:44302/signout-callback-oidc" },// port here should match with sslPort mentioned in launchSetting.json from CorpLense.Inventory.WebClient
AllowOfflineAccess = true,
AllowedScopes = new List<string>
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"InventoryApi" // give this client access to this scope
}
}
};
}
这里是WebApi的Startup.cs
的代码public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
#region Authentication
services.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", options =>
{
options.Authority = Configuration["IdentityServerUri"];
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = false
};
});
#endregion
#region Authorization
services.AddAuthorization(options =>
{
options.AddPolicy("ApiScope", policy =>
{
policy.RequireAuthenticatedUser();
policy.RequireClaim("scope", "InventoryApi");
});
});
#endregion
// register controller services
services.AddControllers()
.AddFluentValidation(fv =>
{
fv.RegisterValidatorsFromAssemblyContaining<Startup>();
fv.DisableDataAnnotationsValidation = true;
});
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "CorpLense.Inventory.WebApi", Version = "v1" });
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
In = ParameterLocation.Header,
Description = "Please Enter Authentication Token",
Name = "InventoryApi",
Type = SecuritySchemeType.ApiKey
});
});
services.AddDbContext<ApplicationContext>(options => options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection"),
b => b.MigrationsAssembly("CorpLense.Inventory.WebApi")));
#region Repositories
services.AddTransient(typeof(IGenericRepository<>), typeof(GenericRepository<>));
services.AddTransient<ISiteRepository, SiteRepository>();
services.AddTransient<IWarehouseRepository, WarehouseRepository>();
#endregion
services.AddTransient<IUnitOfWork, UnitOfWork>();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "CorpLense.Inventory.WebApi v1"));
}
else
{
// register global exception handling service
app.UseExceptionHandler("/Error");
// register global status code error page handling service
app.UseStatusCodePagesWithReExecute("/Error/{0}");
}
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
这里是 WebClient 的代码 Startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie(options =>
{
options.Cookie.Name = "CorpLense.Inventory.WebClient";
})
.AddOpenIdConnect("oidc", options =>
{
options.Authority = Configuration["IdentityServerUri"];
options.ClientId = "CorpLense.Inventory.WebClient";
options.ClientSecret = "4678a2df-9a5d-486d-ba66-d97ae503c1a6";
options.ResponseType = "code";
options.SaveTokens = true;
// ask for required resources
options.Scope.Clear();
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("InventoryApi");
options.Scope.Add("offline_access");
});
services.AddControllersWithViews();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}
这里是 WebClient 主控制器的 Index 方法,它给我错误。
public async Task<IActionResult> Index()
{
// request token
var accessToken = await HttpContext.GetTokenAsync("Cookies","access_token");
// create client
var client = new HttpClient();
// set client's bearer token
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
// request content
var content = await client.GetStringAsync("https://localhost:44301/Sites/GetAllSites");
ViewBag.Json = JArray.Parse(content).ToString(); // PREREQ: Install-Package Newtonsoft.Json
return View();
}
这是出错的代码行。
var content = await client.GetStringAsync("https://localhost:44301/Sites/GetAllSites");
在我的应用程序中,我使用此代码访问令牌:
string idToken = HttpContext.GetTokenAsync("id_token").Result ?? "";
string accessToken = HttpContext.GetTokenAsync("access_token").Result ?? "";
如果没有访问令牌,字符串将为空。
你也可以用属性修饰方法,这样如果用户没有正确认证和授权你甚至不能访问它:
[Authorize]
public async Task<IActionResult> Index()
{
}