[英]Google+/ Facebook Authentication in ASP.NET Core
I've been reading through a lot of guides for getting basic user authentication going using external authentication services, and I just can't get the freaking thing to work. 我已经阅读了很多指南,以使用外部身份验证服务来进行基本的用户身份验证,但我只是无法正常工作。
I started with a "boiler plate" .NET Core project with user-level security. 我从一个具有用户级安全性的“样板” .NET Core项目开始。 I have created my Google and Facebook Auth keys, and included the necessary libraries.
我已经创建了Google和Facebook Auth密钥,并包括了必要的库。 I set my user class like so:
我将用户类设置为:
public class ApplicationUser : IdentityUser<Guid>
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string MiddleName { get; set; }
public string Nickname { get; set; }
}
My Startup.cs file looks like this: 我的Startup.cs文件如下所示:
public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder =
new ConfigurationBuilder().SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", true, true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", true);
if (env.IsDevelopment())
builder.AddUserSecrets();
builder.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddDbContext<ApplicationDbContext>(
options => options.UseNpgsql(Configuration.GetConnectionString("ApplicationDb")));
services.AddIdentity<ApplicationUser, ApplicationRole>(opt =>
{
opt.Password.RequireNonAlphanumeric = false;
opt.Password.RequireUppercase = false;
opt.Password.RequireLowercase = false;
opt.Password.RequireDigit = false;
opt.Password.RequiredLength = 8;
opt.User.RequireUniqueEmail = true;
opt.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-_=+~@.";
opt.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
opt.Lockout.MaxFailedAccessAttempts = 5;
opt.SignIn.RequireConfirmedEmail = true;
opt.SignIn.RequireConfirmedPhoneNumber = false;
})
.AddEntityFrameworkStores<ApplicationDbContext, Guid>()
.AddDefaultTokenProviders();
services.AddMvc(options => { options.Filters.Add(new RequireHttpsAttribute()); });
// Add application services.
services.AddTransient<IEmailSender, AuthMessageSender>();
services.AddTransient<ISmsSender, AuthMessageSender>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseIdentity();
//Add external authentication middleware below.To configure them please see http://go.microsoft.com/fwlink/?LinkID=532715
var facebookOptions = new FacebookOptions
{
AppId = Configuration["Authentication:Facebook:AppId"],
AppSecret = Configuration["Authentication:Facebook:AppSecret"]
};
app.UseFacebookAuthentication(facebookOptions);
var googleOptions = new GoogleOptions
{
ClientId = Configuration["Authentication:Google:AppId"],
ClientSecret = Configuration["Authentication:Google:AppSecret"]
};
app.UseGoogleAuthentication(googleOptions);
app.UseMvc(routes =>
{
routes.MapRoute("default", "{controller=Home}/{action=Index}/{id?}");
});
}
}
So far, so good. 到现在为止还挺好。 I start up the project, click on the "Log In" link, and I can choose to log in with Google or Facebook.
我启动该项目,单击“登录”链接,然后选择使用Google或Facebook登录。 I select Google, and... the first time I try, I get prompted for approval by Google, and pointed back to the Register page, where I create my local account with nickname, etc.
我选择Google,然后...第一次尝试,系统提示我获得Google的批准,并指向“注册”页面,在该页面上我用昵称创建本地帐户,等等。
Now, I can go add a local password to my account. 现在,我可以将本地密码添加到我的帐户了。 All is working swimmingly.
所有人都在努力工作。 So I log off and try to log in again using my Google credentials, after deleting my cookie.
因此,在删除Cookie后,我注销并尝试使用我的Google凭据再次登录。 Surprisingly, I'm brought to the Register page again, but I can't register because I'm already registered.
令人惊讶的是,我再次被带到“注册”页面,但是由于已经注册,所以无法注册。 My local password won't work either.
我的本地密码也不起作用。
So I dig into this a bit more. 因此,我对此进行了更多研究。 In the
AccountController
there is a method called ExternalLoginCallback
where all the magic seems to happen. 在
AccountController
有一个名为ExternalLoginCallback
的方法,似乎所有魔术都在发生。 My method looks like this: 我的方法如下所示:
[HttpGet]
[AllowAnonymous]
public async Task<IActionResult> ExternalLoginCallback(string returnUrl = null, string remoteError = null)
{
if (remoteError != null)
{
ModelState.AddModelError(string.Empty, $"Error from external provider: {remoteError}");
return View(nameof(Login));
}
var info = await _signInManager.GetExternalLoginInfoAsync();
if (info == null)
return RedirectToAction(nameof(Login));
// Sign in the user with this external login provider if the user already has a login.
var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, false);
if (result.Succeeded)
{
_logger.LogInformation(5, "User logged in with {Name} provider.", info.LoginProvider);
return RedirectToLocal(returnUrl);
}
if (result.RequiresTwoFactor)
return RedirectToAction(nameof(SendCode), new
{
ReturnUrl = returnUrl
});
if (result.IsLockedOut)
return View("Lockout");
// If the user does not have an account, then ask the user to create an account.
ViewData["ReturnUrl"] = returnUrl;
ViewData["LoginProvider"] = info.LoginProvider;
var email = info.Principal.FindFirstValue(ClaimTypes.Email);
var firstName = info.Principal.FindFirstValue(ClaimTypes.GivenName);
var lastName = info.Principal.FindFirstValue(ClaimTypes.Surname);
return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel
{
Email = email,
FirstName = firstName,
LastName = lastName
});
}
I trace the code as it goes through the _signInManager.GetExternalLoginInfoAsync()
call, and... the result is NotAllowed
? 我通过
_signInManager.GetExternalLoginInfoAsync()
调用来跟踪代码,并且...结果是NotAllowed
吗?
NotAllowed
is one of 4 possible results, as far as I can tell, the other 3 being Succeeded
, RequiresTwoFactor
, and IsLockedOut
. 据我所知,
NotAllowed
是4种可能结果之一,另外3种是Succeeded
, RequiresTwoFactor
和IsLockedOut
。 The other 3 values get sent someplace else, so I must assume NotAllowed
is expected when no local account exists... except that a local count exists. 其他3个值在其他地方发送,因此我必须假定在不存在本地帐户的情况下期望
NotAllowed
...除了存在本地计数之外。
Can someone give me an idea of what is going on here? 有人可以告诉我这里发生了什么吗? Once I sign off with Google (or Facebook, the same sort of thing happens there), I cannot log back in with them, and there is almost zero useful feedback to determine what the actual problem is.
一旦我与Google(或Facebook)签了字(在那里也发生了类似的事情),我将无法重新登录,并且几乎没有零的有用反馈来确定实际问题是什么。
Never mind; 没关系; I'm an idiot.
我是个白痴。
I thought I was being super cool when I put this line in: 当我把这行代码放进去时,我以为自己很酷:
opt.SignIn.RequireConfirmedEmail = true;
...but, since I wasn't confirming the email, guess what wasn't happening? ...但是,由于我没有确认电子邮件,因此您猜怎么了? SMH...
SMH ...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.