我已经基于.net core 2.2设置了IdentityServer4,并使用OpenIdConnect中间件将Xero配置为外部登录名。我有一个客户端应用程序,用于配置IdentityServer进行身份验证。我希望在客户端应用程序中访问的不仅是IdentityServer的身份验证令牌,还包括外部登录的令牌。有一个MS documentation,建议在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);
} ...
所以登录正常,我在客户端应用程序(asp.net核心)中通过HttpContext.GetTokenAsync("access_token")
获得了Identity Server令牌,但是仍然不知道如何在客户端应用程序中访问外部登录令牌。我不确定是否丢失了某些内容,或者这是否是将外部登录令牌传递到客户端应用程序的正确方法,如果可以,如何访问客户端应用程序中的那些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自己的令牌,最后返回给您的客户端应用程式。 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;
然后,您可以保留所需的任何数据,缓存令牌并返回到客户端,例如,在this sample之类的令牌响应中。