C# 如何在使用OpenID Connect和ASP.NET的第1方应用程序之间实现SSO?
我有一种似乎很奇怪的情况,我不完全确定我是不是走对了路,但接下来 我有一个使用Identity Server实现的OpenId连接提供程序。此OIDC提供程序保护一个API、多个第一方应用程序和多个第三方应用程序。第三方应用程序运行良好。正是第一方应用程序让我很为难,因为我试图在所有这些应用程序中执行SSO,即,如果您登录/退出其中一个应用程序,那么您也会登录/退出其他应用程序。这与您单独登录/注销的第三方应用不同,但它们依赖于您现有的OIDC会话 我的第一方应用程序能够识别来自OIDC提供商的身份验证cookie,因为它们共享相同的数据保护密钥。如果我直接登录到OIDC提供程序,然后导航到第1方应用程序,该应用程序会检测到cookie并指示我已登录 不起作用的是,如果我执行我刚才描述的登录流(直接登录到OIDC提供商,然后导航到第1方应用程序),它实际上从未经过整个OIDC流,因此产生的索赔缺少访问令牌和刷新令牌声明,OIDC通常在命中令牌端点后注入 所以我的问题是:有没有更好的方法来完成我要做的事情,或者有没有一种方法可以强制客户机完成OIDC流,即使它已经有了auth cookie Startup.cs来自第1方应用程序C# 如何在使用OpenID Connect和ASP.NET的第1方应用程序之间实现SSO?,c#,asp.net,cookies,openid-connect,C#,Asp.net,Cookies,Openid Connect,我有一种似乎很奇怪的情况,我不完全确定我是不是走对了路,但接下来 我有一个使用Identity Server实现的OpenId连接提供程序。此OIDC提供程序保护一个API、多个第一方应用程序和多个第三方应用程序。第三方应用程序运行良好。正是第一方应用程序让我很为难,因为我试图在所有这些应用程序中执行SSO,即,如果您登录/退出其中一个应用程序,那么您也会登录/退出其他应用程序。这与您单独登录/注销的第三方应用不同,但它们依赖于您现有的OIDC会话 我的第一方应用程序能够识别来自OIDC提供商的
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);
}
}
});
我并没有完全理解这个场景,但据我所知,您希望更改身份提供程序获得的SSO行为 协议为您提供了控制这一点的能力。身份验证请求可以包含
提示符
参数,以选择与应用程序的所需交互行为
提示
可选。ASCII字符串值的空格分隔、区分大小写的列表
指定授权服务器是否提示最终用户
用于重新验证和同意
有四个参数可供选择(摘自规范章节,无需说明)
- 没有
- 登录
- 同意
- 选择您的帐户
此外,如果您想在top pf prompt参数上强制执行SSO行为,可以使用prompt=none我没有完全理解该场景,但据我所知,您希望更改通过身份提供者获得的SSO行为 协议为您提供了控制这一点的能力。身份验证请求可以包含
提示符
参数,以选择与应用程序的所需交互行为
提示
可选。ASCII字符串值的空格分隔、区分大小写的列表
指定授权服务器是否提示最终用户
用于重新验证和同意
有四个参数可供选择(摘自规范章节,无需说明)
- 没有
- 登录
- 同意
- 选择您的帐户