Ich verwende einen OpenId Connect-Authentifizierungsserver , insbesondere Identity Server 4 (Version 1.5.2) unter .NET Core 1.1. Ich habe dies mit ASP.NET Framework MVC 5 und ASP.NET Core 1.1 MVC-Webanwendungen ausgeführt. Die folgende Konfiguration stammt aus einer .NET Core 1.1-Webanwendung:
public void Configure(
IApplicationBuilder app,
IHostingEnvironment env,
ILoggerFactory loggerFactory)
{
app.UseDeveloperExceptionPage();
app.UseStatusCodePages();
app.UseRewriter(new RewriteOptions().AddRedirectToHttps());
app.UseStaticFiles();
#region Configure Authentication
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
app.UseCookieAuthentication(
new CookieAuthenticationOptions
{
AuthenticationScheme = "Cookies",
AutomaticAuthenticate = true,
AccessDeniedPath = "/AccessDenied"
});
app.UseOpenIdConnectAuthentication(
new OpenIdConnectOptions
{
AuthenticationScheme = "oidc",
SignInScheme = "Cookies",
Authority = "https://localhost:44316",
ClientId = "test-mule",
ClientSecret = "secret",
ResponseType = "code id_token",
SaveTokens = true,
GetClaimsFromUserInfoEndpoint = true,
PostLogoutRedirectUri = "https://localhost:44324",
RequireHttpsMetadata = true,
Scope = { "openid", "profile", "name", "email", "org", "role" },
TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name",
RoleClaimType = "role"
}
});
#endregion Configure Authentication
app.UseMvc();
}
Sobald ich angemeldet bin, kann ich die Ansprüche auflisten, die dem authentifizierten Benutzer zugeordnet sind:
var claims = User.Claims.OrderBy(c => c.Type).ToList();
In der ASP.NET 1.1-Anwendung wird die folgende Anspruchsliste bereitgestellt:
amr pwd
aud test-mule
auth_time 1504529067
c_hash nouhsuXtd5iKT7B33zxkxg
email [email protected]
exp 1504532668
family_name Cobley
given_name Tom
iat 1504529068
idp local
iss https://localhost:44316
name tom
nbf 1504529068
nonce 6364012...
org IBX
role SysAdmin
role TeleMarketing
role AccountManager
role DataManager
role Member
sid 2091...
sub 1b19...440fa
Welches ist, was ich will/erwarte.
Ich versuche jetzt, dieses Verhalten in meiner ersten ASP.NET Core 2.0 -Anwendung mit der folgenden Startup
-Konfiguration zu replizieren:
public Startup()
{
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
}
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication("Cookies")
.AddCookie("Cookies", options =>
{
options.LoginPath = "/SignIn";
options.AccessDeniedPath = "/AccessDenied";
})
.AddOpenIdConnect("oidc", options =>
{
options.SignInScheme = "Cookies";
options.Authority = "https://localhost:44316";
options.ClientId = "test-mule";
options.ClientSecret = "secret";
options.ResponseType = "code id_token";
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.SignedOutRedirectUri = "https://localhost:44367";
options.RequireHttpsMetadata = true;
options.Scope.Clear();
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("name");
options.Scope.Add("email");
options.Scope.Add("org");
options.Scope.Add("role");
options.TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name",
RoleClaimType = "role"
};
});
// Add framework services.
services.AddMvc();
}
Als Referenz sieht die /Signin
controller Aktion so aus:
[Route("/SignIn")]
public IActionResult SignIn(string returnUrl = null)
{
if (!Url.IsLocalUrl(returnUrl)) returnUrl = "/";
var props = new AuthenticationProperties
{
RedirectUri = returnUrl
};
return Challenge(props, "oidc");
}
In dieser Umgebung wird nach einer erfolgreichen Anmeldung, wenn ich die Ansprüche des Benutzers aufführe, nur eine Teilmenge dessen angezeigt, was in Core 1.1 verfügbar ist:
email [email protected]
family_name Cobley
given_name Tom
idp local
name tom.cobley
sid 2091...
sub 1b19...440fa
Ich habe Ablaufverfolgungsprotokolle sowohl auf dem Client als auch auf dem Server ausgeführt, kann jedoch nichts sehen/identifizieren. Ich gehe auch davon aus, dass es sich nicht um ein Identity Server-Problem handelt, da es sich um 'nur' einen Open Id Connect-Dienst handelt, der mit jedem Client konsistent sein sollte.
Kann mich jemand in die richtige Richtung weisen, wo ich falsch liege?
Vielen Dank.
Dem Vorschlag von MVCutter folgend, fügte ich einen OnUserInformationReceived-Ereignishandler hinzu, da ich bemerkt hatte, dass nicht alle meine benutzerdefinierten Ansprüche korrekt der Benutzeridentität zugeordnet wurden. Ich bin mir nicht sicher, warum dies notwendig ist oder ob es einen besseren Ort dafür gibt, aber es scheint mir zu geben, was ich jetzt will.
private Task OnUserInformationReceivedHandler(
UserInformationReceivedContext context)
{
if (!(context.Principal.Identity is ClaimsIdentity claimsId))
{
throw new Exception();
}
// Get a list of all claims attached to the UserInformationRecieved context
var ctxClaims = context.User.Children().ToList();
foreach (var ctxClaim in ctxClaims)
{
var claimType = ctxClaim.Path;
var token = ctxClaim.FirstOrDefault();
if (token == null)
{
continue;
}
var claims = new List<Claim>();
if (token.Children().Any())
{
claims.AddRange(
token.Children()
.Select(c => new Claim(claimType, c.Value<string>())));
}
else
{
claims.Add(new Claim(claimType, token.Value<string>()));
}
foreach (var claim in claims)
{
if (!claimsId.Claims.Any(
c => c.Type == claim.Type &&
c.Value == claim.Value))
{
claimsId.AddClaim(claim);
}
}
}
return Task.CompletedTask;
}
Bitte sehen Sie unten, ich bin auf dasselbe Problem gestoßen wie Sie. Ich bin sicher, dass es ein Konfigurationsproblem gibt, das wir vermissen, aber vorerst habe ich die vom UserInfoEndpoint im OnUserInformationReceived-Ereignishandler zurückgegebenen Werte analysiert.
public override void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(sharedOptions =>
{
sharedOptions.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(o =>
{
o.ClientId = "sss";
o.ClientSecret = "sss";
o.RequireHttpsMetadata = false;
o.Authority = "http://localhost:60000/";
o.MetadataAddress = "http://localhost:60000/IdSrv/.well-known/openid-configuration";
o.ResponseType = OpenIdConnectResponseType.IdTokenToken;
o.CallbackPath = new PathString("/CGI/Home/Index");
o.SignedOutCallbackPath = new PathString("/CGI/Account/LoggedOut");
o.Scope.Add("openid");
o.Scope.Add("roles");
o.SaveTokens = true;
o.GetClaimsFromUserInfoEndpoint = true;
o.Events = new OpenIdConnectEvents()
{
OnUserInformationReceived = (context) =>
{
ClaimsIdentity claimsId = context.Principal.Identity as ClaimsIdentity;
var roles = context.User.Children().FirstOrDefault(j => j.Path == JwtClaimTypes.Role).Values().ToList();
claimsId.AddClaims(roles.Select(r => new Claim(JwtClaimTypes.Role, r.Value<String>())));
return Task.FromResult(0);
}
};
o.TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = JwtClaimTypes.Name,
RoleClaimType = JwtClaimTypes.Role,
};
});
}
Bearbeiten:
Ich fand heraus, dass es eine Erweiterungsmethode für die ClaimsAction-Eigenschaft namens MapUniqueJsonKey gibt. Diese Methode scheint für benutzerdefinierte Schlüssel mit einem Wert zu funktionieren, aber Bomben auf Array-Typen wie Rollen ... rücken näher
o.ClaimActions.MapUniqueJsonKey("UserType", "UserType");
In ASP.NET Core 2 wurde eine ClaimActions-Eigenschaft für OpenIdConnectionOptions eingeführt. Die standardmäßige Sammlung von ClaimActions entfernt die von Ihnen gesuchten Ansprüche. Sie können die Ansprüche zurückerhalten, indem Sie ClaimActions für Ihr Optionsobjekt löschen:
options.ClaimActions.Clear();
Siehe auch: https://leastprivilege.com/2017/11/15/missing-claims-in-the-asp-net-core-2-openid-connect-handler/