简体   繁体   English

.NET CORE API使Facebook登录与Openiddict / Identity一起使用

[英].NET CORE API Making Facebook Login Work With Openiddict/Identity

I have one project (Project A) which is a .NET CORE API project using Openiddict with an endpoint of /connect/token to issue JWT tokens using Identity to handle the security etc. This project works great as is. 我有一个项目(项目A),这是一个使用Openiddict的.NET CORE API项目,其端点为/ connect / token以使用Identity来处理安全性等问题来发行JWT令牌。

I have another project (Project B), which is just a very simple project with some HTML that makes requests to the API to get an access token, and get data from the API. 我有另一个项目(项目B),这是一个非常简单的项目,带有一些HTML,该HTML向API发出请求以获取访问令牌并从API获取数据。 This project also works great. 这个项目也很棒。

Now the part I cannot wrap my brain around, how do I use Facebook login between these two totally separate projects? 现在,我无法解决这个问题,如何在这两个完全独立的项目之间使用Facebook登录? I know how to use it if everything is under one roof, and it's really easy, but this scenario has me totally confused since everything is separated. 如果一切都在一个屋顶下,我知道如何使用它,这确实很容易,但是由于一切都是分开的,所以这种情况使我完全困惑。 So for starters, who handles the 'ExternalLogin', 'ExternalLoginCallBack' logic (from .NET web template using individual accounts), the API? 因此,对于处理“ ExternalLogin”,“ ExternalLoginCallBack”逻辑(使用个人帐户从.NET Web模板)的初学者来说,该API是什么? The HTML project? HTML项目? When connecting with Facebook, what redirect uri should I use (API/HTML project)? 与Facebook连接时,应该使用哪个重定向uri(API / HTML项目)? Then who should have the below code in their 'Startup.cs' file? 那么谁应该在其“ Startup.cs”文件中包含以下代码?

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

And finally if this helps here is how I have Project A currently setup: 最后,如果这有帮助,这是我目前如何设置Project A:

STARTUP.CS (API) STARTUP.CS(API)

public void ConfigureServices function: (API) 公共无效的ConfigureServices函数:(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();

public void Configure function: (API) 公共无效配置功能:(API)

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

Authorization Controller (API) 授权控制器(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."
            });
        }



    }
}

I don't know if it's including anything from Project B since it's pretty basic/bare and relies on the API for everything. 我不知道它是否包含Project B中的任何内容,因为它非常基本/裸露,并且依赖于API进行所有操作。

I know this is a loaded and complicated question, and I'm sure I'm not presenting it as fluidly as possible so I apologize in advance for that, like I said before, I'm confused. 我知道这是一个棘手且复杂的问题,我敢肯定我不会尽可能流畅地提出这个问题,因此我为此事先表示歉意,就像我之前说过的那样,我很困惑。 Thank you! 谢谢!

Now the part I cannot wrap my brain around, how do I use Facebook login between these two totally separate projects? 现在,我无法解决这个问题,如何在这两个完全独立的项目之间使用Facebook登录? I know how to use it if everything is under one roof, and it's really easy, but this scenario has me totally confused since everything is separated. 如果一切都在一个屋顶下,我知道如何使用它,这确实很容易,但是由于一切都是分开的,所以这种情况使我完全困惑。 So for starters, who handles the 'ExternalLogin', 'ExternalLoginCallBack' logic (from .NET web template using individual accounts), the API? 因此,对于处理“ ExternalLogin”,“ ExternalLoginCallBack”逻辑(使用个人帐户从.NET Web模板)的初学者来说,该API是什么? The HTML project? HTML项目?

In the recommended case (ie when using an interactive flow like the authorization code flow or the implicit flow ), the authorization server project itself is responsible of handling the external authentication dance, using the social providers you've configured in your ASP.NET Core pipeline. 在推荐的情况下(即,使用诸如授权代码流或隐式流之类的交互式流时 ),授权服务器项目本身负责使用您在ASP.NET Core中配置的社交提供程序来处理外部身份验证操作。管道。

In theory, the final client application (ie the JS app) doesn't even know that you've decided to use external authentication at the authorization server level, since it's not directly linked to Facebook or Google. 从理论上讲,最终的客户端应用程序(即JS应用程序)甚至不知道您决定在授权服务器级别使用外部身份验证,因为它没有直接链接到Facebook或Google。

In this case, the redirect_uri configured in the Facebook options must correspond to an endpoint owned by the authorization server application (in your case, it's provided by the Facebook authentication middleware). 在这种情况下,在Facebook选项中配置的redirect_uri必须对应于授权服务器应用程序拥有的终结点(在您的情况下,它由Facebook身份验证中间件提供)。


If you don't like this approach, there's also a different flow named "assertion grant" , that basically reverses how things are handled: the final client app (the JS app in your case) is directly linked to Facebook - so the redirect_uri must correspond to the JS app - and uses OpenIddict's token endpoint to "exchange" Facebook tokens with tokens issued by your own server, that can be used with your own APIs. 如果您不喜欢这种方法, 那么还有另一种名为“ assertion grant”的流程 ,该流程基本上颠倒了处理方式:最终的客户端应用程序(在您的情况下为JS应用程序)直接链接至Facebook-因此redirect_uri必须对应于JS应用-并使用OpenIddict的令牌端点将Facebook令牌与您自己的服务器发布的令牌“交换”,该令牌可以与您自己的API一起使用。

For more information about this flow, please read Exchanging a google idToken for local openId token c# . 有关此流程的更多信息,请阅读将Google idToken交换为本地openId令牌c#

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM