我正在尝试使用EF Identity DB设置Identity Server 4解决方案。我可能遇到的问题可能是存储在Identity DB中的信息。不确定我是否有客户端,API,配置,范围...设置正确。这是我第一次尝试使用EF Identity DB。我可以发布数据库信息,如果它有助于解决问题。
我可以登录并检索安全用户声明信息,
Identity Server(来自API的请求)令牌请求验证和令牌验证成功。日志信息如下:
令牌请求验证成功
{
"ClientId": "mvc",
"ClientName": "mvc.client",
"GrantType": "authorization_code",
"AuthorizationCode": "416bf70a2fdfc9b507207e2d2ebaea04b1d26b0dbeab246c3a08c14d4eed0d88",
"Raw": {
"client_id": "mvc",
"client_secret": "***REDACTED***",
"code": "416bf70a2fdfc9b507207e2d2ebaea04b1d26b0dbeab246c3a08c14d4eed0d88",
"grant_type": "authorization_code",
"redirect_uri": "http://localhost:5002/signin-oidc"
}
}
令牌验证成功
{
"ValidateLifetime": true,
"AccessTokenType": "Jwt",
"ExpectedScope": "openid",
"Claims": {
"nbf": 1517178337,
"exp": 1517181937,
"iss": "http://localhost:5000",
"aud": "http://localhost:5000/resources",
"client_id": "mvc",
"sub": "8ae24a28-59f5-48a6-92c6-c6cac551341b",
"auth_time": 1517178333,
"idp": "local",
"scope": [
"openid",
"profile",
"api1"
],
"amr": "pwd"
}
}
但API令牌授权失败。 API失败并显示错误消息:
2018-01-28 17:28:38.011 -05:00 [INF] Failed to validate the token eyJhbGciOiJSUzI1NiIsImtpZCI6IjY3NTYzMGI1NWQ3NWE3OTI4MmNmZWI2OGNiN2I2MDZmIiwidHlwIjoiSldUIn0.eyJuYmYiOjE1MTcxNzgzMzcsImV4cCI6MTUxNzE4MTkzNywiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo1MDAwIiwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdDo1MDAwL3Jlc291cmNlcyIsImNsaWVudF9pZCI6Im12YyIsInN1YiI6IjhhZTI0YTI4LTU5ZjUtNDhhNi05MmM2LWM2Y2FjNTUxMzQxYiIsImF1dGhfdGltZSI6MTUxNzE3ODMzMywiaWRwIjoibG9jYWwiLCJzY29wZSI6WyJvcGVuaWQiLCJwcm9maWxlIiwiYXBpMSJdLCJhbXIiOlsicHdkIl19.meLK1puLfEapFz-sL5IC9NlByfecDDtasPa_Vzba62FZXRJZijlQHysVNRbDKBI5TMqJf3GEs30D4U4T_IoCPz75lkLqCC4XtKROpsIwktm6lpHs-2GEXAZRmhLYDvmlUqwBNmv94XeuiYX8JWm9M-EHIL96Pn4eSlo-ItStgpHCK4sGfSUlTK_CZAfjfgeNXrhR0Sh9ZlXhZyZ5ucyQf8goLSJFk8SkFz3gsNA_gn_L_Q8r7cQk_Sq7Dyqq2YAvTocnwgp8o3UXOEf7h_rGnslLJqLbsnj9Cz8dZPuhknFgP2XZQn1m7ctAuVkz4s4mSJ75g--wYPQ1mJZUHV3l2Q.
Microsoft.IdentityModel.Tokens.SecurityTokenInvalidAudienceException: IDX10214: Audience validation failed. Audiences: 'http://localhost:5000/resources'. Did not match: validationParameters.ValidAudience: 'api1' or validationParameters.ValidAudiences: 'null'.
at Microsoft.IdentityModel.Tokens.Validators.ValidateAudience(IEnumerable`1 audiences, SecurityToken securityToken, TokenValidationParameters validationParameters)
这是API启动类:
#region "ConfigureServices"
public void ConfigureServices(IServiceCollection services)
{
services.AddMvcCore()
.AddAuthorization()
.AddJsonFormatters();
services.AddAuthentication("Bearer")
.AddIdentityServerAuthentication(options =>
{
options.Authority = "http://localhost:5000";
options.RequireHttpsMetadata = false;
options.ApiName = "api1";
});
}
#endregion
#region "Configure"
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseAuthentication();
app.UseMvc();
}
#endregion
这是MVC Client Startup类:
#region "ConfigureServices"
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddOpenIdConnect("oidc", options =>
{
options.SignInScheme = "Cookies";
options.Authority = "http://localhost:5000";
options.RequireHttpsMetadata = false;
options.ClientId = "mvc";
options.ClientSecret = "secret";
options.ResponseType = "code id_token";
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.Scope.Add("api1");
options.Scope.Add("openid");
//options.Scope.Add("offline_access");
});
}
#endregion
#region "Configure"
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseAuthentication();
app.UseStaticFiles();
app.UseMvcWithDefaultRoute();
}
#endregion
以下是Identity Server启动:
#region "ConfigureServices"
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
// Add application services.
services.AddTransient<IEmailSender, EmailSender>();
services.AddMvc();
string connectionString = Configuration.GetConnectionString("DefaultConnection");
var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
// configure identity server with in-memory stores, keys, clients and scopes
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddAspNetIdentity<ApplicationUser>()
// this adds the config data from DB (clients, resources)
.AddConfigurationStore(options =>
{
options.ConfigureDbContext = builder =>
builder.UseSqlServer(connectionString,
sql => sql.MigrationsAssembly(migrationsAssembly));
})
// this adds the operational data from DB (codes, tokens, consents)
.AddOperationalStore(options =>
{
options.ConfigureDbContext = builder =>
builder.UseSqlServer(connectionString,
sql => sql.MigrationsAssembly(migrationsAssembly));
// this enables automatic token cleanup. this is optional.
options.EnableTokenCleanup = true;
options.TokenCleanupInterval = 120; // interval in seconds. 15 seconds useful for debugging
});
services.AddAuthentication()
.AddGoogle("Google", options =>
{
options.ClientId = "434483408261-55tc8n0cs4ff1fe21ea8df2o443v2iuc.apps.googleusercontent.com";
options.ClientSecret = "3gcoTrEDPPJ0ukn_aYYT6PWo";
})
.AddOpenIdConnect("oidc", "OpenID Connect", options =>
{
//options.Authority = "https://demo.identityserver.io/";
//options.ClientId = "implicit";
//options.SaveTokens = true;
options.Authority = "http://localhost:5000";
options.RequireHttpsMetadata = false;
options.SaveTokens = true;
options.ClientId = "mvc";
options.TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name",
RoleClaimType = "role"
};
});
}
#endregion
#region "Configure"
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseBrowserLink();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
// app.UseAuthentication(); // not needed, since UseIdentityServer adds the authentication middleware
app.UseIdentityServer();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
#endregion
MVC客户端控制器:
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authentication;
using System.Net.Http;
using Newtonsoft.Json.Linq;
using IdentityModel.Client;
namespace MvcClient.Controllers
{
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
[Authorize]
public IActionResult Secure()
{
ViewData["Message"] = "Secure page.";
return View();
}
public async Task Logout()
{
await HttpContext.SignOutAsync("Cookies");
await HttpContext.SignOutAsync("oidc");
}
public IActionResult Error()
{
return View();
}
public async Task<IActionResult> CallApiUsingClientCredentials()
{
var tokenClient = new TokenClient("http://localhost:5000/connect/token", "mvc", "secret");
var tokenResponse = await tokenClient.RequestClientCredentialsAsync("api1");
var client = new HttpClient();
client.SetBearerToken(tokenResponse.AccessToken);
var content = await client.GetStringAsync("http://localhost:5001/identity");
ViewBag.Json = JArray.Parse(content).ToString();
return View("json");
}
public async Task<IActionResult> CallApiUsingUserAccessToken()
{
var accessToken = await HttpContext.GetTokenAsync("access_token");
var client = new HttpClient();
client.SetBearerToken(accessToken);
var content = await client.GetStringAsync("http://localhost:5001/identity");
ViewBag.Json = JArray.Parse(content).ToString();
return View("json");
}
}
}
API控制器:
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using IdentityServer4.AccessTokenValidation;
namespace Api.Controllers
{
[Route("[controller]")]
[Authorize(AuthenticationSchemes = IdentityServerAuthenticationDefaults.AuthenticationScheme)]
public class IdentityController : ControllerBase
{
public IActionResult Get()
{
return new JsonResult(from c in User.Claims select new { c.Type, c.Value });
}
}
}
感谢您协助解决此问题并进一步了解我的知识。保罗
答案 0 :(得分:1)
提供的代码不会增加价值。我想看看你是如何配置api1的。您的配置似乎缺少一些东西。下表应包含api1的记录: