转换ASP.Net Core中的Open Id Connect声明
本文关键字:Id Connect 声明 Open 中的 ASP Net Core 转换 | 更新日期: 2023-09-27 18:03:17
我正在编写一个ASP.Net核心Web应用程序,并使用UseOpenIdConnectAuthentication
将其连接到IdentityServer3。模拟他们的ASP.Net MVC 5示例,我试图转换从Identity Server接收回来的声明,以删除"肯定不需要的低级别协议声明"。在MVC 5中,他们添加了一个SecurityTokenValidated Notification的处理程序,该处理程序将AuthenticationTicket
换成只需要声明的声明。
在ASP.Net Core中,为了实现等效功能,我认为需要在OpenIdConnectEvents
中处理OnTokenValidated
。然而,在那个阶段,似乎没有检索到额外的范围信息。如果我处理OnUserInformationReceived
,则存在额外的信息,但存储在用户而不是主体上。
在身份验证完成后,其他事件似乎都不是永久删除我不想保留的声明的明显位置。如有任何建议,不胜感激!
我喜欢LeastPrivilege关于在流程早期进行转换的建议。提供的代码不太有效。这个版本做:
var oidcOptions = new OpenIdConnectOptions
{
...
Events = new OpenIdConnectEvents
{
OnTicketReceived = e =>
{
e.Principal = TransformClaims(e.Ticket.Principal);
return Task.CompletedTask;
}
}
};
这将取代Principal
而不是Ticket
。您可以使用我另一个答案中的代码来创建新的Principal
。你也可以同时更换Ticket
,但我不确定是否有必要。
因此,感谢LeastPrivilege和Adem提出的几乎可以回答我问题的方法。。。只是代码需要稍作调整。总的来说,我更喜欢LeastPrivilege关于尽早转换索赔的建议。
您可以实现SignInScheme
的OnSigningIn
事件。这里有一个例子:
app.UseCookieAuthentication(new CookieAuthenticationOptions()
{
AuthenticationScheme = "OpenIdCookies",
AutomaticAuthenticate = true,
Events = new CookieAuthenticationEvents()
{
OnSigningIn = async (context) =>
{
ClaimsIdentity identity = (ClaimsIdentity)context.Principal.Identity;
identity.Claims = identity.Claims.Where(...);
}
}
});
var oidcOptions = new OpenIdConnectOptions
{
AuthenticationScheme = "oidc",
SignInScheme = "OpenIdCookies"
};
//.. set other options
app.UseOpenIdConnectAuthentication(oidcOptions);
感谢Adem的回复。。。它解决了绝大多数问题。。。唯一的问题是身份。声明是只读属性。我发现创建一个新的校长确实有效:
Events = new CookieAuthenticationEvents()
{
OnSigningIn = (context) =>
{
ClaimsIdentity identity = (ClaimsIdentity)context.Principal.Identity;
var givenName = identity.FindFirst(Constants.ClaimTypes.GivenName);
var familyName = identity.FindFirst(Constants.ClaimTypes.FamilyName);
var sub = identity.FindFirst(Constants.ClaimTypes.Subject);
var claimsToKeep = new List<Claim> {givenName, familyName, sub};
var newIdentity = new ClaimsIdentity(claimsToKeep, identity.AuthenticationType);
context.Principal = new ClaimsPrincipal(newIdentity);
return Task.FromResult(0);
}
}
我不确定这是否是正确的方法,但它似乎有效。
我个人更喜欢在进行实际身份验证的中间件中进行声明转换。
您可以在OIDC中间件上使用OnTicketReceived事件。
var oidcOptions = new OpenIdConnectOptions
{
AuthenticationScheme = "oidc",
SignInScheme = "cookies",
Authority = Clients.Constants.BaseAddress,
ClientId = "mvc.hybrid",
ClientSecret = "secret",
ResponseType = "code id_token",
SaveTokens = true,
TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = JwtClaimTypes.Name,
RoleClaimType = JwtClaimTypes.Role,
},
Events = new OpenIdConnectEvents
{
OnTicketReceived = e =>
{
ClaimsPrincipal p = TransformClaims(e.Ticket.Principal);
e.Ticket = new AuthenticationTicket(
p,
e.Ticket.Properties,
e.Ticket.AuthenticationScheme);
return Task.CompletedTask;
}
}
};
多亏了这个线程中的答案,我自己也能做到这一点。这里没有解决的问题是,如果需要修改索赔,则需要服务。在我的案例中,我需要构建服务提供商,以便获得正确的依赖关系,从而转换声明。(我还可以在不进行转换的情况下删除声明——在这里也显示了代码(。
public void ConfigureServices(IServiceCollection services)
{
services
.AddAuthentication(options =>
{
// set options
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
{
// set options
})
.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
{
// options such as Authority, ClientId, etc set here
options.Authority = "your-value";
options.ClientId = "your-value";
// ...
// remove automatically mapped claims we do not need, keeps the authentication cookie smaller
options.ClaimActions.DeleteClaim("sid");
options.ClaimActions.DeleteClaim("idp");
options.ClaimActions.DeleteClaim("s_hash");
options.ClaimActions.DeleteClaim("auth_time");
options.Events.OnTicketReceived = async context =>
{
// Build the service provider and necessary dependencies
// in order to enhance our claims once we receive it initially
ServiceProvider serviceProvider = services.BuildServiceProvider();
ICustomProvider customProvider = serviceProvider.GetService<ICustomProvider>();
EnhanceClaimsTransformation claimsTransformation = new EnhanceClaimsTransformation(customProvider);
context.Principal = await claimsTransformation.TransformAsync(context.Principal);
await Task.CompletedTask;
};
});
}
增强索赔转换(ICustomProvider在ConfigureServices
中的依赖项注入中注册(
请注意,在这段代码中,我们需要对主体进行克隆,以实际向其添加声明。
public class EnhanceClaimsTransformation : IClaimsTransformation
{
private readonly ICustomProvider _customProvider;
public EnhanceClaimsTransformation(ICustomProvider customProvider)
{
_customProvider = customProvider;
}
/// <summary>
/// Upon authentication, we transform the claims in order to enhance
/// the claims with user-enhanced values.
/// </summary>
/// <param name="principal"></param>
/// <returns></returns>
public async Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
{
// https://gunnarpeipman.com/aspnet-core-adding-claims-to-existing-identity/
ClaimsPrincipal clone = principal.Clone();
ClaimsIdentity claimsIdentity = (ClaimsIdentity)clone.Identity;
Response response = await _customProvider.Find(principal.Identity.Name, CancellationToken.None);
// Setting claims values
claimsIdentity.AddClaims(new List<Claim>
{
new Claim("Datapoint1", response.Datapoint1),
new Claim("Datapoint2", response.Datapoint2),
// ...
});
return clone;
}
}