代码之家  ›  专栏  ›  技术社区  ›  Michel

如何在没有EntityFramework提供程序的情况下在.NET核心中实现Google登录

  •  1
  • Michel  · 技术社区  · 7 年前

    我正在为我的.NET核心站点实现Google登录。

    在本代码中

    var properties = signInManager.ConfigureExternalAuthenticationProperties("Google", redirectUrl);      
    return new ChallengeResult("Google", properties); 
    

    我需要一个 signInManager 其中(通过代码示例)是:

    private SignInManager<AppUser> signInManager;
    

    我通过构造函数注入它,然后得到这个错误:

    试图激活“AccountController”时,无法解析“Microsoft.AspNetCore.Identity.SignInManager1[AppUser]”类型的服务。

    谷歌知道我应该把这个包括进去

    services.AddIdentity<AppUser, IdentityRole>()
        .AddDefaultTokenProviders();`
    

    但这给了我一个错误:

    试图激活“microsoft.aspnetcore.identity.aspnetusermanager1[appuser]”时,无法解析“microsoft.aspnetcore.identity.iuserstore1[appuser]”类型的服务。

    在那一刻,我得到的建议是:

    .AddEntityFrameworkStores<ApplicationDbContext>()
    

    但后来我迷路了,因为为什么 SignInManager 需要一个 IUserStore ,我应该添加一个 UserStore 还有一个 DBContext 和一个 EntityFramework 商店,我什么时候不使用它(为我的谷歌登录)?

    所以问题是:我也可以在没有EntityFramework商店的情况下登录Google吗?

    2 回复  |  直到 7 年前
        1
  •  6
  •   Kirk Larkin    7 年前

    如果你只想登录Google,就不需要 SignInManager , UserManager 或ASP.NET核心标识本身。为了实现这一点,我们首先需要配置身份验证服务。下面是相关的代码,我将在下面解释:

    创业公司

    services
        .AddAuthentication(o =>
        {
            o.DefaultScheme = "Application";
            o.DefaultSignInScheme = "External";
        })
        .AddCookie("Application")
        .AddCookie("External")
        .AddGoogle(o =>
        {
            o.ClientId = ...;
            o.ClientSecret = ...;
        });
    
    • 呼唤 AddAuthentication 配置一个 DefaultScheme 最后被用作 应用程序 方案与 挑战 方案。这个 应用 尝试验证用户身份时使用方案(他们是否登录?). The 挑战 当用户 已登录,但应用程序希望提供这样做的选项。我来讨论一下 DefaultSignInScheme 后来。

    • 两个电话 AddCookie 为两者添加基于cookie的身份验证方案 Application (我们的 应用 方案) External (我们的 信号素 方案)。 加法饼干 也可以采用第二个参数,允许配置相应的cookie的生存期等。

    有了这一点,挑战过程将把用户重定向到 /Account/Login (默认情况下-也可以通过cookie身份验证选项进行配置)。下面是一个控制器实现,它处理挑战过程(稍后我将再次解释):

    会计总监.cs

    public class AccountController : Controller
    {
        public IActionResult Login(string returnUrl)
        {
            return new ChallengeResult(
                GoogleDefaults.AuthenticationScheme,
                new AuthenticationProperties
                {
                    RedirectUri = Url.Action(nameof(LoginCallback), new { returnUrl })
                });
        }
    
        public async Task<IActionResult> LoginCallback(string returnUrl)
        {
            var authenticateResult = await HttpContext.AuthenticateAsync("External");
    
            if (!authenticateResult.Succeeded)
                return BadRequest(); // TODO: Handle this better.
    
            var claimsIdentity = new ClaimsIdentity("Application");
    
            claimsIdentity.AddClaim(authenticateResult.Principal.FindFirst(ClaimTypes.NameIdentifier));
            claimsIdentity.AddClaim(authenticateResult.Principal.FindFirst(ClaimTypes.Email));
    
            await HttpContext.SignInAsync(
                "Application",
                new ClaimsPrincipal(claimsIdentity));
    
            return LocalRedirect(returnUrl);
        }
    }
    

    让我们将其分为两个操作:

    1. Login

      为了到达 登录 操作,用户将 挑战的 . 当用户未使用 应用 方案,但正在尝试访问受 Authorize 属性(或类似)。根据您的要求,如果用户未登录,我们希望使用Google登录。为了实现这一目标,我们发布了 新的 挑战,这次 Google 方案。我们使用 ChallengeResult 配置了 谷歌 方案与A RedirectUrl 它用于在Google登录过程完成后返回我们自己的应用程序代码。如代码所示,我们返回到:

    2. LoginCallback

      这就是 默认签名方案 从我们的呼叫到 添加身份验证 变得相关。作为谷歌登录过程完成的一部分, 默认签名方案 用于设置包含 ClaimsPrincipal 表示从Google返回的用户(这都是在幕后处理的)。中的第一行代码 逻辑回调 抓住这个 索赔委托人 实例,它被包装在 AuthenticateResult 首先要检查是否成功。如果到目前为止一切都成功了,我们最终会创造一个新的 索赔委托人 它包含我们需要的任何声明(在本例中是从Google获取的),然后登录 索赔委托人 使用 应用 方案。最后,我们重定向到导致我们的第一个 挑战 .


    我创建了一个Github存储库,其中包含一个完整的示例,我构建它是为了写出这个答案。 here .


    针对以下评论中的几个后续评论/问题:

    我能得出结论吗 信号管理器 中央层 仅在对数据库使用身份验证时使用?

    在某些方面,是的,我认为这是公平的。虽然可以实现内存中的存储,但是如果没有持久性,它就没有多大意义。但是,在您的情况下不使用这些类的真正原因只是因为您不需要本地用户帐户来表示用户。这与坚持不懈是紧密相连的,但值得加以区分。

    和我在书中读到的(我用来设置我的Google登录)以及我读过的所有其他答案有什么不同。

    文档和书籍涵盖了最常见的用例,因此 希望存储可以 链接 到外部帐户,如google等 信号管理器 源代码,您会发现它实际上只是位于我上面显示的代码类型之上(例如 here here )其他代码可以在默认用户界面中找到(例如 here 以及在 AddIdentity .

    我假设Logincallback被Google调用。httpContext.authenticateAsync知道如何检查Google发送给我的数据吗?由于它的名字非常通用,看起来它知道如何为所有外部提供者做到这一点?

    呼唤 AuthenticateAsync 这里不知道 任何东西 关于google-通过调用配置google特定的处理 AddGoogle 关闭 添加身份验证 在里面 ConfigureServices .在重定向到Google进行登录后,我们实际上回到了 /signin-google 在我们的应用程序中。同样,这是由于 阿德哥格尔 ,但该代码实际上只是在 外部 存储来自谷歌的声明,然后重定向到我们的 登陆车 我们配置的端点。如果您将呼叫添加到 AddFacebook A /sigin-facebook 端点将被配置为执行类似的操作。呼唤 身份验证同步 真的只是补液 索赔原则 从创建的cookie中,例如 谷歌 终结点,以便检索声明。

    值得注意的是,Google/Facebook登录过程基于 OAuth 2 protocol 所以它本身就是一种通用的。如果你需要的不仅仅是Google的支持,你只需要针对所需的方案发布挑战,而不是像我在示例中所做的那样将其硬编码到Google。还可以向挑战添加其他属性,以便能够确定在 登陆车 已到达终结点。

        2
  •  0
  •   tuanv2t    7 年前

    如果不想使用实体框架,则必须自定义存储提供程序: https://docs.microsoft.com/en-us/aspnet/identity/overview/extensibility/overview-of-custom-storage-providers-for-aspnet-identity 如果您想使用实体框架,但得到一些错误(如您所描述的),您可以参考我的源代码演示:

    https://bitbucket.org/tuanv2t/net-core-demo/src/master/NetCoreDemo/GoogleLoginDemo/