【发布时间】:2020-11-20 15:41:26
【问题描述】:
问题
我有三个项目。
- 一个网络应用程序
- API
- 身份服务器
这里有一个快速更新。
我可以使用下面的代码来访问 api 安全性,但是它只会将客户端作为用户传递。
try
{
var client = new HttpClient();
var disco = await client.GetDiscoveryDocumentAsync("https://localhost:44302/");
if (disco.IsError)
{
Console.WriteLine(disco.Error);
}
var tokenResponse = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest
{
Address = disco.TokenEndpoint,
ClientId = "client",
ClientSecret = "secret",
Scope = "crmApi"
});
if (tokenResponse.IsError)
{
Console.WriteLine(tokenResponse.Error);
}
Console.WriteLine(tokenResponse.Json);
//get currently logged on user
//set network credentials/
var httpHandler = new HttpClientHandler();
httpHandler.UseDefaultCredentials = true;
using (HttpClient c = new HttpClient(httpHandler))
{
c.SetBearerToken(tokenResponse.AccessToken);
string page = "https://localhost:44314/weatherforecast";
using (HttpResponseMessage response = await c.GetAsync(page))
using (HttpContent content = response.Content)
{
// ... Read the string.
string result = await content.ReadAsStringAsync();
// ... Display the result.
if (result != null &&
result.Length >= 50)
{
Console.WriteLine(result.Substring(0, 50) + "...");
}
}
}
return View();
}
catch (Exception)
{
throw;
}
这是我看到的,然后我从身份服务器验证客户端。
True; AuthenticationTypes.Federation;
s_hash 8Q2BLwDYoIZ-4IwN4d26MA
sid 1FD1B63201F0B500A4433810F79C1A12
sub 645fd73d-d3b8-48b3-b398-8edd3c9e5b81
auth_time 1596209970
idp local
preferred_username admin
name admin
amr pwd
这是我对 api 的调用
string page = "https://localhost:44314/weatherforecast";
HttpClientHandler httpClientHandler = new HttpClientHandler();
httpClientHandler.UseDefaultCredentials = true;
using (HttpClient client = new HttpClient(httpClientHandler))
{
using (HttpResponseMessage response = await client.GetAsync(page))
using (HttpContent content = response.Content)
{
// ... Read the string.
string result = await content.ReadAsStringAsync();
// ... Display the result.
if (result != null &&
result.Length >= 50)
{
Console.WriteLine(result.Substring(0, 50) + "...");
}
}
}
我遇到的问题是,当我将授权属性添加到 api 控制器时,我无法访问 API。 日志中唯一提到的是承载身份验证受到质疑。
这是来自身份服务器的配置文件
public class Config
{
public static IEnumerable<IdentityResource> GetIdentityResources()
{
return new List<IdentityResource>
{
new IdentityResources.OpenId(),
new IdentityResources.Profile(),
new IdentityResources.Email(),
new IdentityResource
{
Name = "role",
UserClaims = new List<string> {"role"}
}
};
}
public static IEnumerable<ApiResource> GetAllApiResources()
{
return new List<ApiResource>
{
new ApiResource
{
Name = "crmApi",
DisplayName = "API #1",
Description = "Allow the application to access API #1 on your behalf",
Scopes = new List<string> {"crmApi"},
ApiSecrets = new List<Secret> {new Secret("secret".Sha256())}, // change me!
UserClaims = new List<string> {"role"}
}
};
}
public static IEnumerable<ApiScope> GetApiScopes()
{
return new[]
{
new ApiScope("crmApi", "Access to API #1"),
};
}
public static IEnumerable<Client> GetClients()
{
return new List<Client>
{
new Client
{
ClientId = "client",
AllowedGrantTypes = GrantTypes.ClientCredentials,
ClientSecrets =
{
new Secret("secret".Sha256())
},
AllowedScopes = { "crmApi" }
},
new Client
{
ClientId = "mvc",
ClientName = "MVC Client",
AllowedGrantTypes = GrantTypes.Implicit,
RedirectUris = {"https://localhost:44315/signin-oidc"},
PostLogoutRedirectUris = {"https://localhost:44315/signout-callback-oidc"},
AllowedScopes =new List<string>
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Email,
"role",
"crmApi"
}
},
};
}
}
这是身份服务器启动文件
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.AddMvc(option => option.EnableEndpointRouting = false);
var connectionString = Configuration.GetSection("ConnectionStrings:Database").Value;
var migrationAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
services.AddDbContext<ApplicationDbContext>(builder =>
builder.UseSqlServer(connectionString, sqlOptions => sqlOptions.MigrationsAssembly(migrationAssembly)));
services.AddIdentity<IdentityUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddConfigurationStore(options =>
{
options.ConfigureDbContext = b => b.UseSqlServer(connectionString, sql => sql.MigrationsAssembly(migrationAssembly));
})
.AddOperationalStore(options =>
{
options.ConfigureDbContext = b => b.UseSqlServer(connectionString, sql => sql.MigrationsAssembly(migrationAssembly));
})
.AddAspNetIdentity<IdentityUser>();
services.AddCors();
services.AddLogging();
services.AddControllers();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
InitialISDatabase(app);
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseIdentityServer();
app.UseAuthorization();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy(new CookiePolicyOptions { MinimumSameSitePolicy = SameSiteMode.Lax });
app.UseCors();
app.UseMvcWithDefaultRoute();
}
private void InitialISDatabase(IApplicationBuilder app)
{
using (var serviceScope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope())
{
serviceScope.ServiceProvider.GetRequiredService<PersistedGrantDbContext>().Database.Migrate();
serviceScope.ServiceProvider.GetRequiredService<ConfigurationDbContext>().Database.Migrate();
serviceScope.ServiceProvider.GetRequiredService<ApplicationDbContext>().Database.Migrate();
var context = serviceScope.ServiceProvider.GetRequiredService<ConfigurationDbContext>();
var u = serviceScope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
if (!context.Clients.Any())
{
foreach (var client in Config.GetClients())
{
context.Clients.Add(client.ToEntity());
}
context.SaveChanges();
}
if (!context.IdentityResources.Any())
{
foreach (var resource in Config.GetIdentityResources())
{
context.IdentityResources.Add(resource.ToEntity());
}
context.SaveChanges();
}
if (!context.ApiScopes.Any())
{
foreach (var scope in Config.GetApiScopes())
{
context.ApiScopes.Add(scope.ToEntity());
}
context.SaveChanges();
}
if (!context.ApiResources.Any())
{
foreach (var api in Config.GetAllApiResources())
{
context.ApiResources.Add(api.ToEntity());
}
context.SaveChanges();
}
if (!u.Users.Any())
{
var identityUser = new IdentityUser();
identityUser.UserName = "admin";
PasswordHasher<IdentityUser> hasher = new PasswordHasher<IdentityUser>();
identityUser.PasswordHash = hasher.HashPassword(identityUser, "123qwe");
identityUser.Email = "admin@crm.com";
identityUser.NormalizedEmail = "admin@crm.com".ToUpper();
identityUser.NormalizedUserName = "admin".ToUpper();
identityUser.SecurityStamp = Guid.NewGuid().ToString();
u.Users.Add(identityUser);
u.SaveChanges();
}
}
}
这里是api启动文件。
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.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
.AddIdentityServerAuthentication(options =>
{
options.Authority = "https://localhost:44302/";
options.ApiName = "crmApi";
options.RequireHttpsMetadata = false;
});
services.AddAuthorization();
services.AddControllers();
}
// 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.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseHttpsRedirection();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
这里是 web 项目的启动文件。
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.AddControllersWithViews();
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddOpenIdConnect("oidc", options =>
{
options.SignInScheme = "Cookies";
options.Authority = "https://localhost:44302/";
options.RequireHttpsMetadata = false;
options.ClientId = "mvc";
options.SaveTokens = true;
});
}
// 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())
{
}
else
{
app.UseExceptionHandler("/Home/Error");
// 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.UseDeveloperExceptionPage();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}
【问题讨论】:
-
使用jwt授权api为什么没人喜欢jwt技术差没毛病
-
请添加显示您使用访问令牌调用 api 的代码
-
能否请您将日志记录添加到启动类。 services.AddLogging(configure => configure.AddConsole());
-
将凭据发送到 api 是一个问题,我只能让它与客户端凭据一起使用我如何发送用户凭据。
标签: c# model-view-controller identityserver4