я застрял в поиске проблемы, которую я имею здесь.Я пытался найти из вопросов в SO, но мог выяснить проблему.я в отчаянии.
, поэтому в моих решениях есть 3 проекта
API
IdentityServer4
- IdentityServer4
- API-интерфейс управления WebAPI для доступа к клиенту, областям и т. Д. На IdentityServ4
Клиентское приложение
Все прошло нормально.Клиент может войти и пройти аутентификацию через IS4 и получить доступ к производственным ресурсам.теперь возникает необходимость также создать API для управления IS4 из клиентского приложения.но кажется, что я не могу аутентифицироваться, используя тот же токен, выданный IS4.
сообщение в журнале IS4 выглядит следующим образом:
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]
Route matched with {action = "GetUserAccountsList", controller = "Accounts"}. Executing action Identity.API.API.AccountsController.GetUserAccountsList (Identity.API)
dbug: IdentityServer4.AccessTokenValidation.IdentityServerAuthenticationHandler[9]
AuthenticationScheme: Bearer was not authenticated.
info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]
Authorization failed.
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[3]
Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.
info: Microsoft.AspNetCore.Mvc.ChallengeResult[1]
Executing ChallengeResult with authentication schemes (Bearer).
info: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler[12]
AuthenticationScheme: BearerIdentityServerAuthenticationJwt was challenged.
info: IdentityServer4.AccessTokenValidation.IdentityServerAuthenticationHandler[12]
AuthenticationScheme: Bearer was challenged.
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
Executed action Identity.API.API.AccountsController.GetUserAccountsList (Identity.API) in 0.212ms
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 0.6503ms 401
API-код в сети IS4API
[Authorize(AuthenticationSchemes = "Bearer")]
[HttpGet]
public async Task<IActionResult> GetUserAccountsList()
{
var userAccounts = await _accountService.GetIdentityAccountsAsync();
return new JsonResult(userAccounts);
}
и при запуске ConfigureServices
public void ConfigureServices(IServiceCollection services)
{
var dbConnectionName = Constants.Environment.Development;
if (_env.IsProduction())
{
dbConnectionName = Constants.Environment.Production;
}
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString(dbConnectionName), sqlServerOptionsAction: sqlOptions =>
{
sqlOptions.MigrationsAssembly(typeof(Startup).GetTypeInfo().Assembly.GetName().Name);
}));
services.AddIdentity<ApplicationUser, IdentityRole>()
// use this if we want to implement default ASP.NET identity
//services.AddDefaultIdentity<ApplicationUser>()
.AddRoles<IdentityRole>()
.AddRoleManager<RoleManager<IdentityRole>>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
// Configure DI
ConfigureDependencies(services);
services.AddMvc();
#region Registering ASP.NET Identity Server
var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
services.AddIdentityServer(options =>
{
options.IssuerUri = Constants.Address.GetIdentityServerAdress(_env.IsDevelopment());
options.Authentication.CookieLifetime = TimeSpan.FromHours(2);
})
// change to certificate credentials on production
// .AddSigningCredential(Certificate.Get())
.AddDeveloperSigningCredential()
.AddAspNetIdentity<ApplicationUser>()
//// this adds the config data from DB (clients, resources) instead of memory
//.AddInMemoryIdentityResources(Config.GetIdentityResources())
//.AddInMemoryClients(Config.GetClients(_env.IsProduction()))
//.AddInMemoryApiResources(Config.GetApiResources())
.AddConfigurationStore(options =>
{
options.ConfigureDbContext = builder =>
builder.UseSqlServer(Configuration.GetConnectionString(dbConnectionName),
sql => sql.MigrationsAssembly(migrationsAssembly));
})
//// this adds the operational data from DB (codes, tokens, consents)
//.AddInMemoryPersistedGrants()
.AddOperationalStore(options =>
{
options.ConfigureDbContext = builder =>
builder.UseSqlServer(Configuration.GetConnectionString(dbConnectionName),
sql => sql.MigrationsAssembly(migrationsAssembly));
// this enables automatic token cleanup. this is optional.
options.EnableTokenCleanup = true;
options.TokenCleanupInterval = 30;
})
.AddProfileService<IdentityProfileService>(); ;
#endregion Registering ASP.NET Identity Server
services.RegisterApplicationPolicy();
#region External Auth
services.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
.AddIdentityServerAuthentication(options =>
{
options.Authority = Constants.Address.GetIdentityServerAdress(_env.IsDevelopment());
options.RequireHttpsMetadata = false;
options.ApiName = Constants.Resource.Identity;
// options.SupportedTokens = SupportedTokens.Both;
}); ;
#endregion External Auth
}
Startup.cs Настройка
public void Configure(IApplicationBuilder app, UserManager<ApplicationUser> userManager, RoleManager<IdentityRole> roleManager)
{
InitializeDatabase(app, _env, userManager, roleManager);
if (_env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseIdentityServer();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
Клиент включенIS4 заполняется в БД и настраивается следующим образом:
public static class Resource
{
public static List<string> GetAllResourceList()
{
return new List<string>()
{
Clinic,
Subscription,
Module,
Identity // this is IDS4 Server
};
}
// this is used on db seed only.
// resource name has to be updated on DB after db seed
public const string Clinic = "Clinic";
public const string Subscription = "Subscription";
public const string Module = "Module";
public const string Identity = "Identity";
public const string ClinicAddress = "http://localhost:5100";
public const string SubscriptionAddress = "http://localhost:5200";
public const string ModuleAddress = "http://localhost:5300";
public const string IdentityAddress = "http://localhost:5000";
}
public class Config
{
public static IEnumerable<ApiResource> GetApiResources()
{
return Constants.Resource.GetAllResourceList().Select(s => new ApiResource(s));
}
// client want to access resources (aka scopes)
public static IEnumerable<Client> GetClients(bool isDevelopment)
{
var client = new List<Client>();
var mvcClient = new Client
{
ClientId = "mvc",
ClientName = "MVC Client",
AllowedGrantTypes = GrantTypes.HybridAndClientCredentials,
RequireConsent = false,
ClientSecrets =
{
new Secret("secret".Sha256())
},
RedirectUris = { $"{Constants.Address.GetClientServerAdress(isDevelopment)}/signin-oidc" },
PostLogoutRedirectUris =
{$"{Constants.Address.GetClientServerAdress(isDevelopment)}/signout-callback-oidc"},
AlwaysIncludeUserClaimsInIdToken = true,
AllowAccessTokensViaBrowser = true,
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
},
AllowOfflineAccess = true
};
foreach (var resource in Constants.Resource.GetAllResourceList())
{
mvcClient.AllowedScopes.Add(resource);
}
client.Add(mvcClient);
return client;
}
//Add support for the standard openid (subject id) and profile scopes
public static IEnumerable<IdentityResource> GetIdentityResources()
{
return new List<IdentityResource>
{
new IdentityResources.OpenId(),
new IdentityResources.Profile(),
};
}
}
В клиентском приложении Startup.cs выглядит следующим образом
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
// Adding Authentication options+
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddOpenIdConnect("oidc", options =>
{
options.SignInScheme = "Cookies";
options.Authority = $"{Constants.Address.GetIdentityServerAdress(_env.IsDevelopment())}";
options.ClientId = "mvc";
options.ClientSecret = "secret";
options.ResponseType = "code id_token";
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.RequireHttpsMetadata = false;
foreach (var resource in Constants.Resource.GetAllResourceList())
{
options.Scope.Add(resource);
}
options.Scope.Add("offline_access");
options.TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name",
RoleClaimType = "role",
};
});
// Adding Authorisation
services.RegisterApplicationPolicy();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseAuthentication();
app.UseStaticFiles();
app.UseMvcWithDefaultRoute();
}
, где мы пытаемся получить доступ к Web Api на IS4 со следующимкод.Следите за тем, чтобы следующий вызов всегда возвращал 401 Unauthorize
var accessToken = await HttpContext.GetTokenAsync("access_token");
var client = new HttpClient();
client.SetBearerToken(accessToken);
var response = await client.GetAsync($"{Constants.Address.GetIdentityServerAdress(_env.IsDevelopment())}/api/Accounts/GetUserAccountsList");
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
ViewBag.Json = JArray.Parse(content).ToString();
}
else if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
{
return Unauthorized();
}
return View("Json");
Любой совет, как решить проблему, будет полезным.на данный момент я использую проверку подлинности формы для управления клиентом на IS4.