2

我有一个项目(项目 A),它是一个 .NET CORE API 项目,它使用 Openiddict 和 /connect/token 端点来使用 Identity 发布 JWT 令牌来处理安全性等。这个项目按原样工作得很好。

我有另一个项目(项目 B),它只是一个非常简单的项目,其中包含一些 HTML,它向 API 发出请求以获取访问令牌,并从 API 获取数据。这个项目也很好用。

现在我无法绕开我的大脑,我如何在这两个完全独立的项目之间使用 Facebook 登录?如果一切都在一个屋檐下,我知道如何使用它,这真的很容易,但是这种情况让我完全困惑,因为一切都是分开的。那么对于初学者来说,谁处理“ExternalLogin”、“ExternalLoginCallBack”逻辑(来自使用个人帐户的 .NET Web 模板)、API?HTML 项目?与 Facebook 连接时,我应该使用什么重定向 uri(API/HTML 项目)?那么谁应该在他们的“Startup.cs”文件中包含以下代码?

app.UseFacebookAuthentication(new FacebookOptions
{
     AppId = "xxxxxxx",
     AppSecret = "xxxxxxxxx",
     Scope = { "email", "user_friends" },
     Fields = { "name", "email" },
     SaveTokens = true,
});

最后,如果这有帮助,那么我目前如何设置项目 A:

启动.CS (API)

公共无效配置服务功能:(API)

// add entity framework using the config connection string
            services.AddEntityFrameworkSqlServer()
                .AddDbContext<ApplicationDbContext>(options =>
                     options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

            // add identity
            services.AddIdentity<ApplicationUser, ApplicationRole>()
                .AddEntityFrameworkStores<ApplicationDbContext>()
                .AddDefaultTokenProviders();

            // add OpenIddict
            services.AddOpenIddict<ApplicationUser, ApplicationRole, ApplicationDbContext>()
                .DisableHttpsRequirement()
                .EnableTokenEndpoint("/connect/token")
                .AllowPasswordFlow()
                .AllowRefreshTokenFlow()
                .UseJsonWebTokens()
                .AddEphemeralSigningKey();

            services.AddCors();

公共无效配置功能:(API)

 app.UseJwtBearerAuthentication(new JwtBearerOptions
                {
                    AutomaticAuthenticate = true,
                    AutomaticChallenge = true,
                    RequireHttpsMetadata = false,
                    Audience = "http://localhost:54418/",
                    Authority = "http://localhost:54418/"
                });

授权控制器 (API)

public class AuthorizationController : Controller
    {
        private OpenIddictUserManager<ApplicationUser> _userManager;

        public AuthorizationController(OpenIddictUserManager<ApplicationUser> userManager)
        {
            _userManager = userManager;
        }

        [HttpPost("~/connect/token")]
        [Produces("application/json")]
        public async Task<IActionResult> Exchange()
        {
            var request = HttpContext.GetOpenIdConnectRequest();

            if (request.IsPasswordGrantType())
            {
                var user = await _userManager.FindByNameAsync(request.Username);
                if (user == null)
                {
                    return BadRequest(new OpenIdConnectResponse
                    {
                        ErrorDescription = "The username or password provided is incorrect"
                    });
                }

                var identity = await _userManager.CreateIdentityAsync(user, request.GetScopes());

                // Add a custom claim that will be persisted
                // in both the access and the identity tokens.
                if (user.Avatar != null)
                {
                    identity.AddClaim("user_avatar", user.Avatar,
                        OpenIdConnectConstants.Destinations.AccessToken,
                        OpenIdConnectConstants.Destinations.IdentityToken);
                }

                if (user.InSiteUserName != null)
                {
                    identity.AddClaim("insite_username", user.InSiteUserName,
                  OpenIdConnectConstants.Destinations.AccessToken,
                  OpenIdConnectConstants.Destinations.IdentityToken);
                }


                identity.AddClaim("hasLoggedIn", user.HasLoggedIn.ToString(),
              OpenIdConnectConstants.Destinations.AccessToken,
              OpenIdConnectConstants.Destinations.IdentityToken);


                // Create a new authentication ticket holding the user identity.
                var ticket = new AuthenticationTicket(
                    new ClaimsPrincipal(identity),
                    new AuthenticationProperties(),
                    OpenIdConnectServerDefaults.AuthenticationScheme);

                ticket.SetResources(request.GetResources());
                ticket.SetScopes(request.GetScopes());

                return SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme);
            }

            return BadRequest(new OpenIdConnectResponse
            {
                Error = OpenIdConnectConstants.Errors.UnsupportedGrantType,
                ErrorDescription = "The specified grant type is not supported."
            });
        }



    }
}

我不知道它是否包含项目 B 中的任何内容,因为它非常基本/裸露,并且一切都依赖于 API。

我知道这是一个复杂而复杂的问题,而且我确信我没有尽可能流畅地提出它,所以我提前为此道歉,就像我之前说的那样,我很困惑。谢谢!

4

1 回答 1

0

现在我无法绕开我的大脑,我如何在这两个完全独立的项目之间使用 Facebook 登录?如果一切都在一个屋檐下,我知道如何使用它,这真的很容易,但是这种情况让我完全困惑,因为一切都是分开的。那么对于初学者来说,谁处理“ExternalLogin”、“ExternalLoginCallBack”逻辑(来自使用个人帐户的 .NET Web 模板)、API?HTML 项目?

在推荐的情况下(即当使用授权代码流或隐式流之类的交互流时),授权服务器项目本身负责处理外部身份验证舞蹈,使用您在 ASP.NET Core 中配置的社交提供程序管道。

理论上,最终的客户端应用程序(即 JS 应用程序)甚至不知道您已决定在授权服务器级别使用外部身份验证,因为它没有直接链接到 Facebook 或 Google。

在这种情况下,redirect_uriFacebook 选项中的配置必须对应于授权服务器应用程序拥有的端点(在您的情况下,它由 Facebook 身份验证中间件提供)。


如果您不喜欢这种方法,还有一个名为 "assertion grant" 的不同流程,它基本上颠倒了事情的处理方式:最终的客户端应用程序(在您的案例中是 JS 应用程序)直接链接到 Facebook - 所以redirect_uri必须对应到 JS 应用程序 - 并使用 OpenIddict 的令牌端点将 Facebook 令牌与您自己的服务器发布的令牌“交换”,这些令牌可以与您自己的 API 一起使用。

有关此流程的更多信息,请阅读用 google idToken 交换本地 openId 令牌 c#

于 2017-02-05T20:12:33.430 回答