【发布时间】:2018-04-29 08:09:04
【问题描述】:
我的情况似乎很奇怪,我不完全确定我的方法是否正确,但这里是……
我有一个使用 Identity Server 实现的 OpenId Connect 提供程序。此 OIDC 提供商保护一个 API、多个第一方应用程序和多个第三方应用程序。第三方应用程序运行良好。第一方应用程序让我很难过,因为我正在尝试在所有应用程序中进行 SSO,即,如果您登录/退出一个应用程序,那么您也会登录/退出其他应用程序。这与您单独登录/注销但依赖于您现有的 OIDC 会话的 3rd 方应用程序不同。
我的工作是我的第一方应用程序识别来自我的 OIDC 提供商的身份验证 cookie,因为它们共享相同的数据保护密钥。如果我直接登录 OIDC 提供商然后导航到第一方应用程序,该应用程序会检测到 cookie 并指示我已经登录。
不起作用的是,如果我执行刚才描述的登录流程(直接登录 OIDC 提供程序,然后导航到第一方应用程序),它实际上永远不会通过整个 OIDC流,因此生成的 ClaimsIdentity 缺少 OIDC 通常在命中令牌端点后注入的 access_token 和 refresh_token 声明。
所以我的问题是:有没有更好的方法来完成我正在尝试做的事情,或者有没有办法强制客户端完成 OIDC 流程,即使它已经有 auth cookie?
来自第一方应用的 Startup.cs
var dataProtector = //Custom DataProtector
app.SetDefaultSignInAsAuthenticationType("oidc");
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "Cookies",
CookieName = "AuthTicket",
CookieDomain = Properties.Settings.Default.CookieDomain,
CookiePath = "/",
ExpireTimeSpan = TimeSpan.FromDays(20),
LoginPath = new PathString("/Account/Login"),
LogoutPath = new PathString("/Account/Logout"),
TicketDataFormat = new AspNetTicketDataFormat(new DataProtectorShim(dataProtector))
});
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
AuthenticationType = "oidc",
ClientId = Properties.Settings.Default.ClientId,
ClientSecret = Properties.Settings.Default.ClientSecret,
Authority = Properties.Settings.Default.Authority,
RedirectUri = $"{Properties.Settings.Default.BaseSiteUrl}/account/login",
ResponseType = "code id_token",
Scope = "openid profile api",
TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name",
RoleClaimType = "role"
},
SignInAsAuthenticationType = "Cookies",
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthorizationCodeReceived = async n =>
{
var tokenClient = new TokenClient($"{Properties.Settings.Default.Authority}/connect/token",
Properties.Settings.Default.ClientId,
Properties.Settings.Default.ClientSecret);
var tokenResponse = await tokenClient.RequestAuthorizationCodeAsync(n.Code, n.RedirectUri);
if (tokenResponse.IsError)
{
throw new Exception(tokenResponse.Error);
}
// use the access token to retrieve claims from userinfo
var userInfoClient = new UserInfoClient($"{Properties.Settings.Default.Authority}/connect/userinfo");
var userInfoResponse = await userInfoClient.GetAsync(tokenResponse.AccessToken);
// create new identity
var id = new ClaimsIdentity(n.AuthenticationTicket.Identity.AuthenticationType);
id.AddClaims(userInfoResponse.Claims);
if (!string.IsNullOrEmpty(tokenResponse.AccessToken))
{
id.AddClaim(new Claim("access_token", tokenResponse.AccessToken));
id.AddClaim(new Claim("expires_at", DateTime.Now.AddSeconds(tokenResponse.ExpiresIn).ToLocalTime().ToString()));
}
if (!string.IsNullOrEmpty(tokenResponse.RefreshToken))
{
id.AddClaim(new Claim("refresh_token", tokenResponse.RefreshToken));
}
if (!string.IsNullOrEmpty(n.ProtocolMessage.IdToken))
{
id.AddClaim(new Claim("id_token", n.ProtocolMessage.IdToken));
}
if (n.AuthenticationTicket.Identity.Claims.Any(c => c.Type == "sid"))
{
id.AddClaim(new Claim("sid", n.AuthenticationTicket.Identity.FindFirst("sid").Value));
}
n.AuthenticationTicket = new AuthenticationTicket(new ClaimsIdentity(id.Claims, n.AuthenticationTicket.Identity.AuthenticationType, "name", "role"),
n.AuthenticationTicket.Properties);
}
}
});
【问题讨论】:
标签: c# asp.net cookies openid-connect