authentication - 将外部登录令牌从 Identity Server 流向客户端应用程序
问题描述
我已经基于 .net core 2.2 设置了 IdentityServer4,并使用 OpenIdConnect 中间件将 Xero 配置为外部登录。我有一个为身份验证配置 IdentityServer 的客户端应用程序。我喜欢在客户端应用程序中访问的不仅是来自 IdentityServer 的身份验证令牌,还有来自外部登录的令牌。有一个MS 文档建议将外部登录令牌包含在OnGetCallbackAsync
:
var props = new AuthenticationProperties();
props.StoreTokens(info.AuthenticationTokens);
props.IsPersistent = true;
await _signInManager.SignInAsync(user, props);
由于我的 IdentityServer 模板没有OnGetCallbackAsync
方法,我假设从上面的ExternalLoginCallback
操作中实现ExternalLoginController
将完成这项工作(我可能错了):
public async Task<IActionResult> ExternalLoginCallback(string returnUrl = null, string remoteError = null)
{
var context = await _interactionService.GetAuthorizationContextAsync(returnUrl);
if (remoteError != null)
{
ModelState.AddModelError(string.Empty, $"Error from external provider: {remoteError}");
return View($"~/Login/{nameof(LoginController.Login)}");
}
var info = await _signInManager.GetExternalLoginInfoAsync();
if (info == null)
{
return RedirectToAction(nameof(LoginController.Login), "Login");
}
// Sign in the user with this external login provider if the user already has a login.
var result = await _signInManager.ExternalLoginSignInAsync(
info.LoginProvider,
info.ProviderKey,
Constants.AuthenticationProps.Defaults.IsPersistent);
var emailClaim = ClaimTypes.Email;
if (result.Succeeded)
{
var user = await _userManager.FindByNameAsync(info.Principal.FindFirstValue(emailClaim));
var props = new AuthenticationProperties();
props.StoreTokens(info.AuthenticationTokens);
props.IsPersistent = true;
await _signInManager.SignInAsync(user, props, info.LoginProvider);
await _events.RaiseAsync(new UserLoginSuccessEvent(user.Email, user.Id.ToString(), $"{user.GivenName} {user.FamilyName}"));
await _events.RaiseAsync(new UserLoginEvent(user.Id, context?.ClientId));
_logger.LogInformation(5, "User logged in with {Name} provider.", info.LoginProvider);
return RedirectToLocal(returnUrl);
} ...
所以登录工作正常,我HttpContext.GetTokenAsync("access_token")
在客户端应用程序(asp.net core)中获得了身份服务器令牌,但仍然无法弄清楚如何在客户端应用程序中访问外部登录令牌。我不确定我是否遗漏了什么,或者这是否是将外部登录令牌流向我的客户端应用程序的正确方法,如果是,如何访问AuthenticationTokens
客户端应用程序中的那些?
这是我的客户端应用程序 openidconnect 配置供参考:
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = "oidc";
})
.AddCookie(
CookieAuthenticationDefaults.AuthenticationScheme,
options =>
{
options.ExpireTimeSpan = TimeSpan.FromMinutes(30);
options.Cookie.Name = "xero";
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
})
.AddOpenIdConnect("oidc", options =>
{
options.Authority = "https://localhost:44333";//IdentityServer address
options.RequireHttpsMetadata = true;
options.ClientId = "MyAppClientId";
options.ClientSecret = "MyAppClientSecret";
options.ResponseType = "code id_token";
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.Scope.Clear();
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("email");
options.ClaimActions.MapAllExcept("iss", "nbf", "exp", "aud", "nonce", "iat", "c_hash");
options.TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = JwtClaimTypes.Name,
RoleClaimType = JwtClaimTypes.Role
};
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true
};
options.Events = new OpenIdConnectEvents
{
OnRedirectToIdentityProvider = ctx =>
{
if (ctx.ProtocolMessage.RequestType == Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectRequestType.Authentication)
{
ctx.ProtocolMessage.AcrValues = "idp:xero";
}
return Task.CompletedTask;
}
};
});
解决方案
如果在 Identity Server 中实现外部登录,Identity server 从外部提供者接收到 id 令牌/访问令牌后,它将解码令牌并获取用户的声明,登录用户,然后创建身份服务器自己的令牌,最后返回到您的客户端应用程序。Identity Server 不会处理来自外部提供者的令牌,但您可以通过以下Callback
方法获取令牌ExternalController
:
var result = await HttpContext.AuthenticateAsync(IdentityServer4.IdentityServerConstants.ExternalCookieAuthenticationScheme);
//get the tokens
var tokens = result.Properties.GetTokens();
var idToken = tokens.Where(x => x.Name.Equals("id_token")).FirstOrDefault().Value;
然后,您可以保留所需的任何数据、缓存令牌并返回到客户端,例如,在此示例中的令牌响应中。当然,您的客户端应用程序也可以在身份验证后发出另一个请求以获取令牌(在 中保留令牌ExternalController
)。
推荐阅读
- php - CSS 不会链接到我在 Wordpress 中的 page.php 模板,其他一切正常
- html - 如何仅使用 html 和 scss 在元素之前和之后分配不同的背景颜色?
- plot - 几个问题: 1. 打开或关闭枢轴高低功能。2.改变标签偏移距离
- python - 每次迭代后清空列表
- c# - C# Xamarin 在 TabbedPage 中使用 ObservableCollection 形成嵌套列表
- python-3.x - 如何使用 matplotlib 调整大小并显示带有补丁的裁剪图像?
- android - Koin 和 Kotlin:不能使用 T 作为具体参数
- c# - GTK TreeView 复选框留给文本?
- php - 计算其他表中每个 id 的行数包含与使用活动记录的外键相同的 id
- c# - Visual Studio 2019 不会在项目打开时拉取所需的 Docker 映像