将外部登录令牌从Identity Server流到客户端应用程序 [英] Flow external login tokens from the Identity Server to the client app
问题描述
我已经基于.net core 2.2设置了IdentityServer4,并使用OpenIdConnect中间件将Xero配置为外部登录.我有一个客户端应用程序,用于配置IdentityServer进行身份验证.我希望在客户端应用程序中访问的不仅是来自IdentityServer的身份验证令牌,还包括来自外部登录的令牌.有一个 MS文档,建议将外部登录令牌包括在OnGetCallbackAsync
中:
I have setup IdentityServer4 based on .net core 2.2 and configured Xero as an External Login using OpenIdConnect middleware. I have a client app which configures the IdentityServer for Authentication. What I like to access in the client app is not only authentication tokens from the IdentityServer but also the tokens from External login. There is a MS documentation which suggests to include the external login tokens in OnGetCallbackAsync
:
var props = new AuthenticationProperties();
props.StoreTokens(info.AuthenticationTokens);
props.IsPersistent = true;
await _signInManager.SignInAsync(user, props);
由于我的IdentityServer模板没有OnGetCallbackAsync
方法,因此我假设在上述ExternalLoginController
中的ExternalLoginCallback
动作中实现该功能(我可能错了):
Since my IdentityServer template doesn't have OnGetCallbackAsync
method, I assumed implementing above in ExternalLoginCallback
action from ExternalLoginController
will do the job (I may be wrong):
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);
} ...
因此登录正常,我在客户端应用程序(asp.net核心)中通过HttpContext.GetTokenAsync("access_token")
获取了Identity Server令牌,但是仍然不知道如何在客户端应用程序中访问外部登录令牌.我不确定是否丢失了某些东西,或者这是否是将外部登录令牌流到客户端应用程序的正确方法,以及是否可以在客户端应用程序中访问那些AuthenticationTokens
?
So the login is working and I get Identity Server tokens by HttpContext.GetTokenAsync("access_token")
in the client app(asp.net core) however still can't figure out how to access external login tokens in the client app. I'm not sure if I'm missing something or whether this is the correct approach to flow the external login tokens to my client app and if so how to access those AuthenticationTokens
in the client app?
这是我的客户端应用程序openidconnect配置以供参考:
here is my client app openidconnect configuration for reference :
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;
}
};
});
推荐答案
我通过在ExternalLoginCallback
中添加缺少的部分来使其工作.我替换了以下代码:
I got it working by adding a missing part in ExternalLoginCallback
. I replaced the following codes:
var props = new AuthenticationProperties();
props.StoreTokens(info.AuthenticationTokens);
props.IsPersistent = true;
await _signInManager.SignInAsync(user, props, info.LoginProvider);
有这行:
await _signInManager.UpdateExternalAuthenticationTokensAsync(info);
await _signInManager.UpdateExternalAuthenticationTokensAsync(info);
将外部登录凭据(access_token
,expires_at
,id_token
,refresh_token
和token_type
)保存在 [dbo].[UserTokens]
中的Identity SQL DB中.
接下来,我需要以某种方式从表中获取数据.
Which saves the external login credentials(access_token
, expires_at
, id_token
, refresh_token
and token_type
) in Identity SQL DB in [dbo].[UserTokens]
.
All I need next is to fetch the data from the Table in some way.
在身份令牌中包含这些凭据不是一个好主意,并且可能会使响应头过大,并且客户端请求可能会失败,因此我实现了由我的客户端应用通过发送用户ID和接收外部令牌来调用的API. 感谢@NanYu的提示.
Including those credentials in Identity token is not a great idea and can make the response header too big and client request may fail so I implemented an API to be called by my client app by sending user id and receiving external tokens. Thanks to @NanYu for the hint.
这篇关于将外部登录令牌从Identity Server流到客户端应用程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!