使用Cookie时,有没有一种标准方法可以让使用ID4 OIDC中间件的MVC客户端刷新ClaimsPrincipal?如果要求中间件刷新ClaimsPrincipal会很好,但我不认为该功能存在。
下面的代码确实有效,但是,下面的示例中没有使用nonce - 所以我不确定这是否安全。我不确定中间件是如何创建现时的。
有没有人有一个使用带有ID4 OIDC中间件的cookie在MVC客户端应用程序中正确刷新ClaimsPrincipal的示例?
private ClaimsPrincipal ValidateIdentityToken(string idToken, DiscoveryResponse disco )
{
var keys = new List<SecurityKey>();
foreach (var webKey in disco.KeySet.Keys)
{
var e = Base64Url.Decode(webKey.E);
var n = Base64Url.Decode(webKey.N);
var key = new RsaSecurityKey(new RSAParameters { Exponent = e, Modulus = n });
key.KeyId = webKey.Kid;
keys.Add(key);
}
var parameters = new TokenValidationParameters
{
ValidIssuer = disco.TryGetString(OidcConstants.Discovery.Issuer),
ValidAudience = "mvc.hybrid",
IssuerSigningKeys = keys,
NameClaimType = JwtClaimTypes.Name,
RoleClaimType = JwtClaimTypes.Role
};
var handler = new JwtSecurityTokenHandler();
handler.InboundClaimTypeMap.Clear();
SecurityToken token;
var user = handler.ValidateToken(idToken, parameters, out token);
//var nonce = user.FindFirst("nonce")?.Value ?? "";
//if (!string.Equals(nonce, "random_nonce")) throw new Exception("invalid nonce");
//nonce is always ""
return user;
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationScheme = "Cookies",
AutomaticAuthenticate = true,
ExpireTimeSpan = TimeSpan.FromMinutes(60),
Events = new CookieAuthenticationEvents()
{
OnValidatePrincipal = async cookiecontext =>
{
if (cookiecontext.Properties.Items.ContainsKey(".Token.expires_at"))
{
var expire = DateTime.Parse(cookiecontext.Properties.Items[".Token.expires_at"]);
if (expire <= DateTime.Now.AddMinutes(-5) || DateTime.Now > expire)
{
var disco = await DiscoveryClient.GetAsync("http://localhost:5000");
if (disco.IsError) throw new Exception(disco.Error);
var refreshToken = cookiecontext.Properties.Items[".Token.refresh_token"];
var tokenClient = new TokenClient(disco.TokenEndpoint,
"mvc.hybrid",
"secret");
var response = await tokenClient.RequestRefreshTokenAsync(refreshToken);
if (!response.IsError)
{
cookiecontext.Properties.Items[".Token.access_token"] = response.AccessToken;
cookiecontext.Properties.Items[".Token.refresh_token"] = response.RefreshToken;
cookiecontext.Properties.Items[".Token.expires_at"] = DateTime.Now.AddSeconds((int)response.ExpiresIn).ToString();
cookiecontext.Properties.Items["NextAccessTokenRefresh"] = DateTime.Now.AddMinutes(5).ToString();
var _Princ = ValidateIdentityToken(response.IdentityToken, disco);
cookiecontext.ReplacePrincipal(_Princ);
cookiecontext.ShouldRenew = true;
}
else
{
cookiecontext.RejectPrincipal();
}
}
}
}
}
});
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions
{
AuthenticationScheme = "oidc",
SignInScheme = "Cookies",
Authority = "http://localhost:5000",
RequireHttpsMetadata = false,
ClientId = "mvc.hybrid",
ClientSecret = "secret",
ResponseType = "code id_token",
Scope = { "openid", "profile", "email", "api1", "offline_access", "role" },
GetClaimsFromUserInfoEndpoint = true,
Events = new OpenIdConnectEvents()
{
OnTicketReceived = notification =>
{
notification.Response.Cookies.Append("NextAccessTokenRefresh", DateTime.Now.AddMinutes(5).ToString());
return Task.FromResult(0);
}
},
SaveTokens = true,
TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
{
NameClaimType = JwtClaimTypes.Name,
RoleClaimType = JwtClaimTypes.Role,
}
});
}