如何将 WebApi ChallengeResult 合并到 Angular2 SPA 中?

Tom*_*Tom 5 c# asp.net-core asp.net-core-webapi angular

语境

我们正在将使用 Asp.Net Core (Web Api) 的 Web 应用程序迁移到使用 Angular2 单页应用程序 (SPA) 前端。该应用程序最初是使用“个人用户帐户”进行的。我们已经将 cshtml 视图转换为 Angular2 组件,将控制器方法转换为生成 Json,甚至合并 JWT 进行身份验证。

我一直在使用这个配置谷歌身份验证微软文档。

问题

通过以下两种控制器方法说明了该问题。该LinkLogin方法返回一个ChallengeResult动作。显然这不能转换为 JSON。我认为这个结果应该会导致浏览器重定向到外部登录提供程序,然后自动重定向到LinkLoginCallback.

    [HttpPost]
    public async Task<IActionResult> LinkLogin([FromBody] string provider)
    {
        // Clear the existing external cookie to ensure a clean login process
        await HttpContext.Authentication.SignOutAsync(externalCookieScheme);

        // Request a redirect to the external login provider to link a login for the current user
        string redirectUrl = Url.Action(nameof(LinkLoginCallback), "Manage");
        var properties = signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl, userManager.GetUserId(User));
        return Challenge(properties, provider);
    }

    [HttpPost]
    [Produces("application/json")]
    public async Task<ActionResult> LinkLoginCallback()
    {
        User user = await userManager.GetUserAsync(User);
        if (user == null)
            return Json(false);

        ExternalLoginInfo info = await signInManager.GetExternalLoginInfoAsync(await userManager.GetUserIdAsync(user));
        if (info == null)
            return Json(false);

        IdentityResult result = await userManager.AddLoginAsync(user, info);
        if (result.Succeeded)
        {
            // Clear the existing external cookie to ensure a clean login process
            await HttpContext.Authentication.SignOutAsync(externalCookieScheme);
            return Json(true);
        }

        return Json(false);
    }
Run Code Online (Sandbox Code Playgroud)

如果我尝试LinkLogin从 Angular 调用,我会收到以下响应:

对预检请求的响应未通过访问控制检查:请求的资源上不存在“Access-Control-Allow-Origin”标头。因此,不允许访问来源“ http://localhost:53462 ”。响应的 HTTP 状态代码为 405。

Tom*_*Tom 0

因此,我最终提出了一个解决方案,通过修改 Angular2 和 WebApi 之间的流程来避免“ChallengeResult”。

  1. 将 npm 包添加angular2-social-login到 Angular 应用程序中(遵循所有简单的设置说明)。
  2. 将两种控制器方法合并为一种。该ExternalLoginViewModel参数是一个简单的类,具有 Email、ProviderKey 和 LoginProvider 属性(在步骤 3 中以 Angular 填充):

    [HttpPost]
    [Produces("application/json")]
    public async Task<ActionResult> LinkLogin([FromBody] ExternalLoginViewModel info)
    {
        if (ModelState.IsValid)
        {
            User user = await userManager.GetUserAsync(User);
            if (user != null)
            {
                IdentityResult result = await userManager.AddLoginAsync(user, new UserLoginInfo(info.LoginProvider, info.ProviderKey, info.LoginProvider));
                if (result.Succeeded)
                    return Json(true);
            }
        }
        return Json(false);
    }
    
    Run Code Online (Sandbox Code Playgroud)
  3. 更改了 Angular2 客户端以使用社交媒体包来获取 Web API 所需的凭据。这是我LinkProvider演示连接的方法:(this.service.LinkLogin调用LinkLogin控制器方法)

    public async LinkProvider(providerName: string): Promise<void>
    {
        const result: any = await this.auth.login(providerName).toPromise();
        const success: boolean = await this.service.LinkLogin({
             email: result.email,
             loginProvider: result.provider,
             providerKey: result.uid
        });
    
        // Handle link response here
    }
    
    Run Code Online (Sandbox Code Playgroud)