在使用Google作为外部登录提供商时,我正在尝试修复间歇性问题。
尝试登录时,会将用户重定向回登录页面,而不是进行身份验证。
问题出现在这一行(下面的链接第55行),GetExternalIdentityAsync返回null。
var externalIdentity = await AuthenticationManager.GetExternalIdentityAsync(DefaultAuthenticationTypes.ExternalCookie);
完整的代码是:
[Authorize]
public abstract class GoogleAccountController<TUser> : Controller where TUser : Microsoft.AspNet.Identity.IUser
{
public IAuthenticationManager AuthenticationManager
{
get
{
return HttpContext.GetOwinContext().Authentication;
}
}
public abstract UserManager<TUser> UserManager { get; set; }
[AllowAnonymous]
[HttpGet]
[Route("login")]
public ActionResult Login(string returnUrl)
{
ViewData.Model = new LoginModel()
{
Message = TempData["message"] as string,
Providers = HttpContext.GetOwinContext().Authentication.GetExternalAuthenticationTypes(),
ReturnUrl = returnUrl
};
return View();
}
[AllowAnonymous]
[HttpPost]
[ValidateAntiForgeryToken]
[Route("login")]
public ActionResult Login(string provider, string returnUrl)
{
return new ChallengeResult(provider, Url.Action("Callback", "Account", new { ReturnUrl = returnUrl }));
}
[AllowAnonymous]
[Route("authenticate")]
public async Task<ActionResult> Callback(string returnUrl)
{
var externalIdentity = await AuthenticationManager.GetExternalIdentityAsync(DefaultAuthenticationTypes.ExternalCookie);
if (externalIdentity == null)
{
return RedirectToAction("Login", new { ReturnUrl = returnUrl });
}
var emailAddress = externalIdentity.FindFirstValue(ClaimTypes.Email);
var user = await UserManager.FindByNameAsync(emailAddress);
if (user != null)
{
await SignInAsync(user, false);
return RedirectToLocal(returnUrl);
}
else
{
TempData.Add("message", string.Format("The account {0} is not approved.", emailAddress));
return RedirectToAction("Login", new { ReturnUrl = returnUrl });
}
}
[HttpPost]
[ValidateAntiForgeryToken]
[Route("logout")]
public ActionResult Logout(string returnUrl)
{
AuthenticationManager.SignOut();
return RedirectToLocal(returnUrl);
}
private async Task SignInAsync(TUser user, bool isPersistent)
{
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
var authenticationProperties = new AuthenticationProperties()
{
IsPersistent = isPersistent
};
AuthenticationManager.SignIn(authenticationProperties, identity);
}
private ActionResult RedirectToLocal(string returnUrl)
{
if (Url.IsLocalUrl(returnUrl))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
protected override void Dispose(bool disposing)
{
if (disposing && UserManager != null)
{
UserManager.Dispose();
UserManager = null;
}
base.Dispose(disposing);
}
}
这也是here。
这是一个非常间歇性的问题,重新部署应用程序通常会让它暂时起作用。
在Fiddler中查看我可以看到只是在身份验证方法之前签名google的电话,在该方法中找不到cookie。
该应用使用以下代码初始化Google登录
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/login")
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
app.UseGoogleAuthentication();
我已在web.config中将身份验证模式设置为non,并删除了表单身份验证模块。
<system.web>
<authentication mode="None" />
</system.web>
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<modules runAllManagedModulesForAllRequests="true">
<remove name="FormsAuthenticationModule" />
</modules>
</system.webServer>
这些网站托管在Azure上,有些在1个实例上运行,有些运行在2个。 他们有自定义域,但在自定义域和azurewebsites域以及http / https上仍然失败。
任何人都可以帮忙解决为什么会这样吗?
更新
Microsoft.Owin.Security.Google 3.0版于昨晚发布。要切换,看看是否能解决问题。
https://www.nuget.org/packages/Microsoft.Owin.Security.Google
答案 0 :(得分:2)
我忘了在google开发者控制台中启用“Google + API”。 Google登录似乎没问题,但GetExternalLoginInfoAsync返回null。
答案 1 :(得分:2)
Microsoft的System.Web Owin实现中存在一个错误。在IIS上运行Owin应用程序时使用的那个。如果我们在ASP.NET MVC5中使用基于Owin的新身份验证处理,那么我们99%的人可能会这样做。
臭虫使Owin设置的cookie在某些情况下神秘地消失。
之前将此nuget放在https://github.com/KentorIT/owin-cookie-saver之前
app.UseGoogleAuthentication(...)
答案 2 :(得分:1)
Tom我使用REST API在我的asp.net应用程序中使用google-oauth。它工作正常,我没有遇到任何连接问题。
我正在执行以下步骤:
1.我在谷歌开发者控制台中创建了一个项目,因为我创建了“Web应用程序的客户端ID”设置,其中包含以下参数。
a)客户ID =&gt;它将由谷歌自动生成 b)电子邮件地址=&gt;它将由谷歌自动生成 c)客户秘密=&gt;它将由谷歌自动生成 d)重定向URI =&gt;需要指定将用于处理身份验证过程的网页的URL。在此页面中,我们可以进行身份验证,我们可以获取用户的基本信息。
my url: "http://localhost:1822/WebForm1.aspx/code"
我设置了“Webpage2.aspx”启动页面,我在“Webpage2.aspx”中构建了开放的auth url并重定向到google登录页面。
登录后,它将重定向到“Webpage1.aspx”以及访问代码。通过将此访问代码传递给“https://accounts.google.com/o/oauth2/token”url,我将获得访问令牌以及令牌类型和令牌到期时间。之后通过将此访问权限传递给“https://www.googleapis.com/oauth2/v2/userinfo”网址,我将获得用户基本信息,如“电子邮件,姓名,性别,照片等......”
public class GoogleAuthorizationData
{
public string access_token { get; set; }
public int expires_in { get; set; }
public string token_type { get; set; }
}
public class GoogleUserInfo
{
public string name { get; set; }
public string family_name { get; set; }
public string gender { get; set; }
public string email { get; set; }
public string given_name { get; set; }
public string picture { get; set; }
public string link { get; set; }
public string id { get; set; }
}
Webpage1.aspx
============
protected void Page_Load(object sender, EventArgs e)
{
string code = Request.QueryString["code"].ToString();
string scope = Request.QueryString["scope"].ToString();
string url = "https://accounts.google.com/o/oauth2/token";
string postString = "code=" + code + "&client_id=" + ConfigurationManager.AppSettings["GoogleClientID"].ToString() + "&client_secret=" + ConfigurationManager.AppSettings["GoogleSecretKey"].ToString() + "&redirect_uri=" + ConfigurationManager.AppSettings["ResponseUrl"].ToString() + "&grant_type=authorization_code";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url.ToString());
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
UTF8Encoding utfenc = new UTF8Encoding();
byte[] bytes = utfenc.GetBytes(postString);
Stream os = null;
try
{
request.ContentLength = bytes.Length;
os = request.GetRequestStream();
os.Write(bytes, 0, bytes.Length);
}
catch
{ }
try
{
HttpWebResponse webResponse = (HttpWebResponse)request.GetResponse();
Stream responseStream = webResponse.GetResponseStream();
StreamReader responseStreamReader = new StreamReader(responseStream);
var result = responseStreamReader.ReadToEnd();//
var json = new JavaScriptSerializer();
GoogleAuthorizationData authData = json.Deserialize<GoogleAuthorizationData>(result);
HttpWebRequest request1 = (HttpWebRequest)WebRequest.Create("https://www.googleapis.com/oauth2/v2/userinfo");
request1.Method = "GET";
request1.ContentLength = 0;
request1.Headers.Add("Authorization", string.Format("{0} {1}", authData.token_type, authData.access_token));
HttpWebResponse webResponse1 = (HttpWebResponse)request1.GetResponse();
Stream responseStream1 = webResponse1.GetResponseStream();
StreamReader responseStreamReader1 = new StreamReader(responseStream1);
GoogleUserInfo userinfo = json.Deserialize<GoogleUserInfo>(responseStreamReader1.ReadToEnd());
Response.Write(userinfo.email);
}
catch (Exception eX)
{
throw eX;
}
}
答案 3 :(得分:1)
我相信你不应该使用app.UseGoogleAuthentication();
因为这是一个试图使用OpenID 2.0的电话has been deprecated。
您应该使用的是OAuth 2.0 for Login (OpenID Connect)
所以:
app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions() { ClientId = "YOUR_CLIENT_ID", ClientSecret = "YOUR_CLIENT_SECRET", });
答案 4 :(得分:1)
我有同样的问题。我使用的是Visual Studio 2013,网站是在Azure上。社交日志一直没有问题停止工作,LinkLoginCallback在loginInfo中收到null。我重新发布项目没有代码更改或重建,然后loginInfo收到正确的数据,一切正常。没有意义,但你去了。
答案 5 :(得分:1)
昨天我遇到了这个问题而且我完全被抢走了! 而且,正如你所描述的那样,我毫无理由地得到了它。
我设法修复它(经过几个小时的比较2个项目 - 一个测试项目每次都没有问题,另一个是一个更严肃的项目 - 他们有完全相同的代码,但不同的dll版本)
问题出在DLL上 - 来自Nuget的引用包。 确保您拥有最新的软件包,并查看 web.config 中的运行时部分。
我更新了所有与Owin相关的软件包和Microsoft.Owin并添加了:
<assemblyBinding>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Owin.Security" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Owin.Security.Cookies" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Owin.Security.OAuth" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
</dependentAssembly>
</assemblyBinding>
......它再次奏效! 它们可能会根据您使用的包装而有所不同,但这就是我的工作方式。
答案 6 :(得分:0)
确保已启用第三方Cookie。我发现如果您在尝试“注册”时没有登录谷歌。如果用户使用您的应用程序,它会重定向到登录页面,因为它会查找不存在的cookie,但仍然可以通过外部提供程序完成所需的操作。下次您尝试注册时,由于它已完成部分流程,因此不再需要查找外部cookie,因此第二次成功。