Open Closed

How to integration external identity? #2278


User avatar
0
ldacnfinit created
  • ABP Framework version: v4.4.3
  • UI type: Angular
  • DB provider: EF Core
  • Tiered Identity Server Separated (Angular): yes
  • Exception message and stack trace:

InvalidOperationException: SignInAsync when principal.Identity.IsAuthenticated is false is not allowed when AuthenticationOptions.RequireAuthenticatedSignIn is true. Microsoft.AspNetCore.Authentication.AuthenticationService.SignInAsync(HttpContext context, string scheme, ClaimsPrincipal principal, AuthenticationProperties properties) IdentityServer4.Hosting.IdentityServerAuthenticationService.SignInAsync(HttpContext context, string scheme, ClaimsPrincipal principal, AuthenticationProperties properties) Siemens.LDA.CleanOrder.Controllers.AuthenticationController.ExternalLoginBackAsync() in AuthenticationController.cs await HttpContext.SignInAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme, lambda_method1783(Closure , object ) Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor+TaskOfActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, object controller, object[] arguments) System.Threading.Tasks.ValueTask<TResult>.get_Result()

  • Steps to reproduce the issue:"

    • ConfigureAuthentication
         context.Services.AddAuthentication(options=>
            {
                //options.RequireAuthenticatedSignIn = false;
            })
                .AddJwtBearer(options =>
                {
                    options.Authority = configuration["AuthServer:Authority"];
                    options.RequireHttpsMetadata = Convert.ToBoolean(configuration["AuthServer:RequireHttpsMetadata"]);
                    options.Audience = "CleanOrder";
                    options.BackchannelHttpHandler = new HttpClientHandler
                    {
                        ServerCertificateCustomValidationCallback =
                            HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
                    };
                })       //.AddCookie("CleanOrder.MyId")
       .AddOpenIdConnect("MyId", "OpenID Connect", options =>
         {
             options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
             options.SignOutScheme = IdentityServerConstants.SignoutScheme;
             options.Authority = "https://myid.siemens.com/";
             options.CallbackPath = "/";
             options.ClientSecret = configuration["MyIdAuthServer:ClientSecret"];
             options.ClientId = configuration["MyIdAuthServer:ClientId"];
             options.ResponseType = OpenIdConnectResponseType.Code;
             options.SaveTokens = true;
             //options.SignedOutRedirectUri = "http://localhost:4300";
             options.BackchannelHttpHandler = new HttpClientHandler
             {
                 ServerCertificateCustomValidationCallback =
                            HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
             };       
    
    • Environment (Angular)
    oAuthConfig: {
    issuer: 'https://myid.siemens.com',
    redirectUri: 'https://localhost:44361/authentication/token',
    clientId: 'ClienID',
    responseType: 'code',
    scope: 'openid profile email',
    }
    
    • Controller
     [HttpGet("token")]
        public ActionResult AuthAsync()
        {
            Console.WriteLine("===========token==================");
            var callbackUrl = Url.Action("ExternalLoginback");
            var properties = new AuthenticationProperties()
            {
                // actual redirect endpoint for your app
                RedirectUri = callbackUrl,
                AllowRefresh = true,
            };
            return Challenge(properties, "MyId");
        }
    
        [HttpGet("signin-oidc")]
        public async Task<RedirectResult> ExternalLoginBackAsync()
        {
            Console.WriteLine("===========callback==================");
            // read external identity from the temporary cookie
            var result = await HttpContext.AuthenticateAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme);
            if (result?.Succeeded != true)
            {
                throw new Exception("External authentication error");
            }
    
            // retrieve claims of the external user
            var externalUser = result.Principal;
            if (externalUser == null)
            {
                throw new Exception("External authentication error");
            }
    
            // retrieve claims of the external user
            var claims = externalUser.Claims.ToList();
    
            // try to determine the unique id of the external user - the most common claim type for that are the sub claim and the NameIdentifier
            // depending on the external provider, some other claim type might be used
            var userIdClaim = claims.FirstOrDefault(x => x.Type == JwtClaimTypes.Subject);
            if (userIdClaim == null)
            {
                userIdClaim = claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier);
            }
            if (userIdClaim == null)
            {
                throw new Exception("Unknown userid");
            }
    
            var externalUserId = userIdClaim.Value;
            var externalProvider = userIdClaim.Issuer;
    
            // get userInfo
            var user = await _appUserService.GetByUserNameAsync(externalUserId.Split('|')[1]);
            var clientUrl = _configuration["App:ClientUrl"];
            if (user != null)
            {
                              // issue authentication cookie for user
                await HttpContext.SignInAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme,
                    new ClaimsPrincipal(
                        new ClaimsIdentity(
                                    new List<Claim>
                                    {
                                    new Claim(AbpClaimTypes.UserId,user.Id.ToString()),
                                    new Claim(AbpClaimTypes.UserName,user.UserName),
                                    new Claim(AbpClaimTypes.Email,user.Email)
                                    }
                                )
                    )
              );
                //delete temporary cookie used during external authentication
                //await HttpContext.SignOutAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme);
            }
            else
            {
                clientUrl += "/userNotExsit";
            }
            return Redirect(clientUrl);
        }
    

It is the first time to integrate third-party authentication system. I have limited knowledge of authentication and experience with JWT Access Token. I need help.


11 Answer(s)
  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    Hi,

    Can you try testing external login with IdentityServer and check the logs?

  • User Avatar
    0
    ldacnfinit created

    你好。我已经完成了第三方认证部分,获得了所需的用户信息,并且在数据库中查到了该用户,现在需要做的是登录并且返回到客户端站点,但我遇到了一个如上所示的异常信息,如果我将 ConfigureAuthentication 中的 RequireAuthenticatedSignIn 设置为 false 后,该问题即不存在,会跳转到客户端,但是并没有登录成功。希望能得到您的帮助。谢谢!

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    Hi,

    Can you share a project to reproduce? shiwei.liang@volosoft.com thanks.

  • User Avatar
    0
    ldacnfinit created

    很抱歉,因为第三方的认证需要内网才可以进行,这意味着您无法进行认证的调试,所以您是否还需要项目?

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    Hi,

    You can try to integration external login without ABP application, if what works you can share the project with us, we can help you implement it in the ABP application.

  • User Avatar
    0
    ldacnfinit created

    Hi, 我已经卡在这个问题上一天了,经过修改已经可以实现不设置 RequireAuthenticatedSignIn = false 使用 HttpContext.SingIn 不会报错,代码改动如下:

      var isUser = new IdentityServerUser(user.Id.ToString());
                    var principal = isUser.CreatePrincipal();
                    principal.AddIdentity(
                    new ClaimsIdentity(
                                    new List<Claim>
                                    {
                                        new Claim(AbpClaimTypes.UserId,user.Id.ToString()),
                                        new Claim(AbpClaimTypes.UserName,user.UserName),
                                        new Claim(AbpClaimTypes.Email,user.Email)
                                    }
                                )
                        );
                    await HttpContext.SignInAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme, principal);
    
    

    但在跳转回 Angular 时,https://localhost:44361/api/abp/application-configuration 接口返回的仍然是没有登录,返回结果如下图所示:

    所以我的问题的关键在于如何使当前用户登录上去,这块我理解的不到位,是否是根据 cookie 或者 access token 来实现校验的?api/abp/application-configuration 接口的源代码链接方便发我一下么。 另外想问下是否提供远程协助。

    PS:不使用 Abp 框架中的 angular 部分, 采用 asp.net 来测试是否可以跑通,我认为意义不是很大。

    随时期待您的回复。

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    You can use Github as an external login to check the entire process.

    Create a new project with angular as UI then add AddGitHub

    https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers

  • User Avatar
    0
    ldacnfinit created

    好的。我将会试试使用 GitHub认证,跑下整个流程。

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    ok

  • User Avatar
    0
    ldacnfinit created

    已经在开发环境解决了认证授权问题,但是在部署到生产环境时,在请求第三方认证站点时出现了CORS 问题,部署环境为 IIS,请问如何解决这个问题。 尝试过以下两种方案: 第一种,使用 Angular Proxy config,但是没生效 第二种,将 oAuthConfigissuer设置为源站,在 IIS 中将请求转发到认证站点,但出现了新问题 main-es2015.22bb79fb162f00377e5b.js:1 invalid issuer in discovery document expected: https://源站.com.cn current: https://认证.xxx.com,所以还是需要使用第一种,直接解决跨域的问题

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    Please create a new question(English).

Made with ❤️ on ABP v9.1.0-preview. Updated on December 05, 2024, 12:19