我正在为.net核心网站实现Google登录。

在这段代码中

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

我需要一个signInManager(通过代码示例),它是:
private SignInManager<AppUser> signInManager;

我通过构造函数注入(inject)它,然后出现此错误:



谷歌搜索得知我应该包括此内容
services.AddIdentity<AppUser, IdentityRole>()
    .AddDefaultTokenProviders();`

但这给了我这个错误:



在那一刻,我得到建议添加以下内容:
.AddEntityFrameworkStores<ApplicationDbContext>()

但是后来我迷路了,因为为什么SignInManager需要IUserStore,我应该添加一个UserStoreDBContextEntityFramework存储,什么时候不使用(用于Google登录)?

所以问题是:如果没有Entityframework存储,我也可以登录Google吗?

最佳答案

如果您要做的只是使用Google登录,就不需要SignInManagerUserManager或ASP.NET Core Identity本身。为此,我们首先需要配置身份验证服务。这是与此相关的代码,我将在后面解释:
Startup.cs

services
    .AddAuthentication(o =>
    {
        o.DefaultScheme = "Application";
        o.DefaultSignInScheme = "External";
    })
    .AddCookie("Application")
    .AddCookie("External")
    .AddGoogle(o =>
    {
        o.ClientId = ...;
        o.ClientSecret = ...;
    });
  • 调用AddAuthentication可配置DefaultScheme,最终将其同时用作Application方案和Challenge方案。尝试对用户进行身份验证时使用“应用”方案(他们是否登录?)。当用户未登录但应用程序希望提供登录选项时,将使用“挑战”方案。稍后我将讨论DefaultSignInScheme
  • AddCookie的两个调用为Application(我们的应用程序方案)和External(我们的登录方案)添加了基于cookie的身份验证方案。 AddCookie也可以采用第二个参数,该参数允许配置例如相应cookie的生存期等

  • 有了这个,挑战过程将把用户重定向到/Account/Login(默认情况下-也可以通过cookie身份验证选项进行配置)。这是一个处理挑战过程的 Controller 实现(同样,我会在后面解释):
    AccountController.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);
        }
    }
    
    让我们将其分解为两个 Action :
  • Login为了达到Login Action ,用户将受到挑战。当用户未使用Application方案登录但尝试访问受Authorize属性(或类似属性)保护的页面时,会发生这种情况。根据您的要求,如果用户未登录,我们希望使用Google进行登录。为了实现这一点,我们这次针对Google方案提出了一个新的挑战。我们使用ChallengeResultGoogle进行配置,该RedirectUrl配置了LoginCallback方案,并且DefaultSignInScheme用于在Google登录过程完成后返回我们自己的应用程序代码。如代码所示,我们返回到:
  • AddAuthentication这是我们对DefaultSignInScheme的调用中的ClaimsPrincipal变得相关的地方。作为Google登录过程的一部分,LoginCallback用于设置cookie,该cookie包含代表从Google返回的用户的ClaimsPrincipal(所有操作均在后台进行)。 AuthenticateResult中的第一行代码捕获了这个ClaimsPrincipal实例,该实例被包装在一个ClaimsPrincipal中,该Application首先被检查是否成功。如果到目前为止一切顺利,我们最终将创建一个包含所需声明的新SignInManager(在本例中为Google提出),然后使用AddIdentity方案登录该AuthenticateAsync。最后,我们重定向到引起我们第一个挑战的页面。

  • 针对以下评论中的一些后续评论/问题:

    在某些方面,是的,我认为这很公平。尽管可以实现内存存储,但没有持久性并没有多大意义。但是,在您的情况下不使用这些类的真正原因仅仅是因为您不需要代表用户的本地用户帐户。这与持久性是并驾齐驱的,但值得区别对待。

    文档和书籍涵盖了最常见的用例,因此您确实想存储可以链接到外部帐户(例如Google等)的本地用户。如果查看AddGoogle源,您会发现它实际上只是坐在我上面显示的那种代码之上(例如herehere)。其他代码可在默认用户界面(例如here)和 AddAuthentication 中找到。

    此处对ConfigureServices的调用对Google一无所知-特定于Google的处理是通过从/signin-google中的AddGoogle调用External来配置的。重定向到Google进行登录后,我们实际上回到了应用程序中的LoginCallback。同样,这要归功于对AddFacebook的调用,但是该代码实际上只是在/sigin-facebook方案中发布了一个cookie,该cookie存储从Google返回的声明,然后重定向到我们配置的AuthenticateAsync端点。如果您添加对ClaimsPrincipal的调用,则会将/signin-google端点配置为执行类似操作。实际上,对LoginCallback的调用只是从例如由以下代码创建的cookie中补充ojit_code的水分。 ojit_code端点,以便检索声明。
    还值得注意的是,Google/Facebook登录过程基于OAuth 2 protocol,因此它本身是通用的。如果您不仅需要对Google的支持,您将对所需的方案提出挑战,而不是像在示例中所做的那样将其硬编码到Google。也可以向质询添加其他属性,以便能够确定在到达ojit_code端点时使用了哪个提供程序。

    我创建了一个GitHub存储库,其中包含一个完整的示例,该示例是我为编写此答案here而构建的。

    关于c# - 如何在没有 Entity Framework 提供程序的情况下在.net核心中实现google登录,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/53654020/

    10-16 23:56