Here is the setup for the Identity server configuration
var builder = services.AddIdentityServer(options =>
{
options.Events.RaiseErrorEvents = true;
options.Events.RaiseInformationEvents = true;
options.Events.RaiseFailureEvents = true;
options.Events.RaiseSuccessEvents = true;
options.EmitStaticAudienceClaim = true;
})
.AddProfileService<ProfileService>()
// this adds the config data from DB (clients, resources, CORS)
.AddConfigurationStore(options =>
{
options.ConfigureDbContext = builder =>
builder.UseSqlServer(configuration.GetConnectionString("DefaultConnection"),
sql => sql.MigrationsAssembly(migrationsAssembly));
})
// this adds the operational data from DB (codes, tokens, consents)
.AddOperationalStore(options =>
{
options.ConfigureDbContext = builder =>
builder.UseSqlServer(configuration.GetConnectionString("DefaultConnection"),
sql => sql.MigrationsAssembly(migrationsAssembly));
// this enables automatic token cleanup. this is optional.
options.EnableTokenCleanup = true;
});
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
configuration.GetConnectionString("DefaultConnection"),
b => b.MigrationsAssembly("Falcon-Identity")));
services.AddIdentity<ApplicationUser, IdentityRole>(
options =>
{
options.SignIn.RequireConfirmedAccount = true;
options.Password.RequireDigit = false;
options.Password.RequiredLength = 8;
options.Password.RequireLowercase = true;
options.Password.RequireUppercase = false;
})
.AddEntityFrameworkStores<ApplicationDbContext>();
// not recommended for production - you need to store your key material somewhere secure
builder.AddDeveloperSigningCredential();
builder.AddInMemoryApiScopes(Config.ApiScopes);
// Register the IConfiguration instance which options binds against.
services.Configure<IdentityServerViewModel>(configuration.GetSection("IdentityServer"));
app configuration
app.UseRouting();
app.UseIdentityServer();
app.UseAuthorization();
Client configuration
public static IEnumerable<Client> Clients(IConfiguration configuration) =>
new Client[]
{
new Client
{
ClientId = configuration.GetSection("IdentityServer:Client:ClientId").Value,
ClientName = configuration.GetSection("IdentityServer:Client:ClientName").Value,
//AllowedCorsOrigins = new List<string> { "http://localhost:4200","https://localhost:4200" },
AllowedGrantTypes = GrantTypes.Code,
AllowAccessTokensViaBrowser = bool.Parse(configuration.GetSection("IdentityServer:Client:AllowAccessTokensViaBrowser").Value),
AccessTokenLifetime=86400,
RequireConsent = bool.Parse(configuration.GetSection("IdentityServer:Client:RequireConsent").Value),
UpdateAccessTokenClaimsOnRefresh = bool.Parse(configuration.GetSection("IdentityServer:Client:UpdateAccessTokenClaimsOnRefresh").Value),
RedirectUris = LocalRedirectUris(configuration),
PostLogoutRedirectUris = LocalRedirectUris(configuration),
AllowedScopes = AllowedScopes(),
AllowOfflineAccess = bool.Parse(configuration.GetSection("IdentityServer:Client:AllowOfflineAccess").Value),
AccessTokenType = AccessTokenType.Jwt,
RequireClientSecret = bool.Parse(configuration.GetSection("IdentityServer:Client:RequireClientSecret").Value),
RequirePkce = bool.Parse(configuration.GetSection("IdentityServer:Client:RequirePkce").Value),
//AllowRememberConsent = true
}
};
private static ICollection<string> AllowedScopes()
{
return new List<string>
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Email,
AuthorizePolicy.apiScope
};
}
// API scopes represent values that describe scope of access and can be requested by the scope parameter (OAuth)
public static readonly IEnumerable<ApiScope> ApiScopes =
new[]
{
new ApiScope(IdentityServerConstants.StandardScopes.OpenId),
new ApiScope(IdentityServerConstants.StandardScopes.Profile),
new ApiScope(IdentityServerConstants.StandardScopes.Email),
new ApiScope(AuthorizePolicy.apiScope),
};
Account controller
if (ModelState.IsValid)
{
// validate username/password against in-memory store
var result = await _signInManager.PasswordSignInAsync(model.Username, model.Password,
model.RememberLogin, lockoutOnFailure: true);
// validate username/password against in-memory store
if (result.Succeeded)
{
var user = await _userManager.FindByNameAsync(model.Username);
await _events.RaiseAsync(new UserLoginSuccessEvent(user.UserName, user.Id, user.Email, clientId: context?.Client.ClientId));
// only set explicit expiration here if user chooses "remember me".
// otherwise we rely upon expiration configured in cookie middleware.
AuthenticationProperties props = null;
if (AccountOptions.AllowRememberLogin && model.RememberLogin)
{
props = new AuthenticationProperties
{
IsPersistent = true,
ExpiresUtc = DateTimeOffset.UtcNow.Add(AccountOptions.RememberMeLoginDuration)
};
};
// Add the additional claim to the Identity and token
var principal = await _claimsFactory.CreateAsync(user);
var claims = principal.Claims.ToList();
// issue authentication cookie with subject ID and username
var isuser = new IdentityServerUser(user.Id)
{
DisplayName = user.UserName,
AdditionalClaims = claims
};
await HttpContext.SignInAsync(isuser, props);
if (context != null)
{
if (context.IsNativeClient())
{
// The client is native, so this change in how to
// return the response is for better UX for the end user.
return this.LoadingPage("Redirect", model.ReturnUrl);
}
// we can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null
return Redirect(model.ReturnUrl);
}
// request for a local page
if (Url.IsLocalUrl(model.ReturnUrl))
{
return Redirect(model.ReturnUrl);
}
else if (string.IsNullOrEmpty(model.ReturnUrl))
{
return Redirect("~/");
}
else
{
// user might have clicked on a malicious link - should be logged
throw new Exception("invalid return URL");
}
}
await _events.RaiseAsync(new UserLoginFailureEvent(model.Username, "invalid credentials", clientId:context?.Client.ClientId));
ModelState.AddModelError(string.Empty, AccountOptions.InvalidCredentialsErrorMessage);
}
Error
System.InvalidOperationException: idp claim is missing
at IdentityServer4.Extensions.PrincipalExtensions.GetIdentityProvider(IIdentity identity)
at IdentityServer4.Extensions.PrincipalExtensions.GetIdentityProvider(IPrincipal principal)
at IdentityServer4.ResponseHandling.AuthorizeInteractionResponseGenerator.ProcessLoginAsync(ValidatedAuthorizeRequest request)
at IdentityServer4.ResponseHandling.AuthorizeInteractionResponseGenerator.ProcessInteractionAsync(ValidatedAuthorizeRequest request, ConsentResponse consent)
at IdentityServer4.Endpoints.AuthorizeEndpointBase.ProcessAuthorizeRequestAsync(NameValueCollection parameters, ClaimsPrincipal user, ConsentResponse consent)
at IdentityServer4.Endpoints.AuthorizeEndpoint.ProcessAsync(HttpContext context)
at IdentityServer4.Hosting.IdentityServerMiddleware.Invoke(HttpContext context, IEndpointRouter router, IUserSession session, IEventService events, IBackChannelLogoutService backChannelLogoutService)
2021-01-07 07:14:50.419 +00:00 [ERR] An unhandled exception has occurred while executing the request.
System.InvalidOperationException: idp claim is missing
at IdentityServer4.Extensions.PrincipalExtensions.GetIdentityProvider(IIdentity identity)
at IdentityServer4.Extensions.PrincipalExtensions.GetIdentityProvider(IPrincipal principal)
at IdentityServer4.ResponseHandling.AuthorizeInteractionResponseGenerator.ProcessLoginAsync(ValidatedAuthorizeRequest request)
at IdentityServer4.ResponseHandling.AuthorizeInteractionResponseGenerator.ProcessInteractionAsync(ValidatedAuthorizeRequest request, ConsentResponse consent)
at IdentityServer4.Endpoints.AuthorizeEndpointBase.ProcessAuthorizeRequestAsync(NameValueCollection parameters, ClaimsPrincipal user, ConsentResponse consent)
at IdentityServer4.Endpoints.AuthorizeEndpoint.ProcessAsync(HttpContext context)
at IdentityServer4.Hosting.IdentityServerMiddleware.Invoke(HttpContext context, IEndpointRouter router, IUserSession session, IEventService events, IBackChannelLogoutService backChannelLogoutService)
at IdentityServer4.Hosting.IdentityServerMiddleware.Invoke(HttpContext context, IEndpointRouter router, IUserSession session, IEventService events, IBackChannelLogoutService backChannelLogoutService)
at IdentityServer4.Hosting.MutualTlsEndpointMiddleware.Invoke(HttpContext context, IAuthenticationSchemeProvider schemes)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at IdentityServer4.Hosting.BaseUrlMiddleware.Invoke(HttpContext context)
at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.<Invoke>g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task)
2021-01-07 08:36:56.305 +00:00 [INF] Starting IdentityServer4 version 4.1.1+cebd52f5bc61bdefc262fd20739d4d087c6f961f
2021-01-07 08:36:56.410 +00:00 [INF] Using the default authentication scheme Identity.Application for IdentityServer
2021-01-07 08:36:56.411 +00:00 [DBG] Using Identity.Application as default ASP.NET Core scheme for authentication
2021-01-07 08:36:56.412 +00:00 [DBG] Using Identity.External as default ASP.NET Core scheme for sign-in
2021-01-07 08:36:56.412 +00:00 [DBG] Using Identity.External as default ASP.NET Core scheme for sign-out
2021-01-07 08:36:56.413 +00:00 [DBG] Using Identity.Application as default ASP.NET Core scheme for challenge
2021-01-07 08:36:56.413 +00:00 [DBG] Using Identity.Application as default ASP.NET Core scheme for forbid
2021-01-07 08:36:56.865 +00:00 [DBG] Login Url: /Account/Login
2021-01-07 08:36:56.872 +00:00 [DBG] Login Return Url Parameter: ReturnUrl
2021-01-07 08:36:56.873 +00:00 [DBG] Logout Url: /Account/Logout
2021-01-07 08:36:56.873 +00:00 [DBG] ConsentUrl Url: /consent
2021-01-07 08:36:56.874 +00:00 [DBG] Consent Return Url Parameter: returnUrl
2021-01-07 08:36:56.875 +00:00 [DBG] Error Url: /home/error
2021-01-07 08:36:56.875 +00:00 [DBG] Error Id Parameter: errorId
Tried the solution from these references, but not working for me.
https://github.com/IdentityServer/IdentityServer4/issues/1792 https://github.com/IdentityServer/IdentityServer4/issues/1878
JWT Token
{
"nbf": 1610250740,
"exp": 1610250790,
"iss": "https://falconidentityserver.azurewebsites.net",
"aud": "https://falconidentityserver.azurewebsites.net/resources",
"client_id": "Falcon_Identity_Server",
"sub": "e413120a-2aa3-43e9-a450-eee670cca321",
"auth_time": 1610250389,
"idp": "local",
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier": "e413120a-2aa3-43e9-a450-eee670cca321",
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name": "admin@local.com",
"AspNet.Identity.SecurityStamp": "d5fe7709-9d7d-4a08-a246-8e1ae0536bde",
"IdentityServer": [
"Read",
"Create",
"Update",
"Delete"
],
"jti": "CA316689F3B2F0F702CF10E63B6F4EA9",
"sid": "23AF4158F934C003DD6552614E26E600",
"iat": 1610250740,
"scope": [
"openid",
"profile",
"email"
],
"amr": [
"pwd"
]
}
Have you tried configuring the SecurityStampValidator to retain the idp claim, following the instructions linked here?
https://github.com/IdentityServer/IdentityServer4/issues/1878
Apparently, ASP.NET Identity drops the idp claims from the cookies after the browser has been idle for some time. To prevent that add the following to the ConfigureServices method in Startup.cs of the ASP.NET Core project.
builder.Services.Configure<SecurityStampValidatorOptions>(opts =>
{
opts.OnRefreshingPrincipal = SecurityStampValidatorCallback.UpdatePrincipal;
});
(Requires IdentityServer4.AspNetIdentity package)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.