将外部登录令牌从Identity Server流到客户端应用程序 [英] Flow external login tokens from the Identity Server to the client app

查看:123
本文介绍了将外部登录令牌从Identity Server流到客户端应用程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经基于.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_tokenexpires_atid_tokenrefresh_tokentoken_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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆