我正在开发一个使用Google+进行外部身份验证的ASP.NET MVC 5应用程序。我在console.developers.google.com上创建了一个项目,获得了appID和appSecret。以下是UI和代码。我无法发布图片,因为我需要10个以上的声誉:(。我的登录屏幕包含呈现所有ExternalLogin提供商的部分视图。我已按以下方式注册Google提供商。
public partial class Startup
{
// For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
public void ConfigureAuth(IAppBuilder app)
{
// Configure the db context, user manager and signin manager to use a single instance per request
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
// Enable the application to use a cookie to store information for the signed in user
// and to use a cookie to temporarily store information about a user logging in with a third party login provider
// Configure the sign in cookie
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider
{
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add an external login to your account.
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
}
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
// Enables the application to temporarily store user information when they are verifying the second factor in the two-factor authentication process.
app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5));
// Enables the application to remember the second login verification factor such as phone or email.
// Once you check this option, your second step of verification during the login process will be remembered on the device where you logged in from.
// This is similar to the RememberMe option when you log in.
app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);
// Uncomment the following lines to enable logging in with third party login providers
//app.UseMicrosoftAccountAuthentication(
// clientId: "",
// clientSecret: "");
//app.UseTwitterAuthentication(
// consumerKey: "",
// consumerSecret: "");
//app.UseFacebookAuthentication(
// appId: "",
// appSecret: "");
app.UseGoogleAuthentication("xxxxxxxxxx_my_appID",
"xxxxx_my_appsecret");
}
来自RouteConfig.cs的代码
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.MapRoute(
name: "signin-google",
url: "signin-google",
defaults: new { controller = "Account", action = "ExternalLoginCallback" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
点击&#34;使用Google登录&#34;按钮,调用以下代码。
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult ExternalLogin(string provider, string returnUrl)
{
// Request a redirect to the external login provider
return new ChallengeResult(provider, Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl }));
}
[AllowAnonymous]
public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
{
var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
if (loginInfo == null)
{
return RedirectToAction("Login");
}
//This will fetch the USERPROFILE from google
if (loginInfo.Login.LoginProvider == "Google")
{
var externalIdentity = AuthenticationManager.GetExternalIdentityAsync(DefaultAuthenticationTypes.ExternalCookie);
var emailClaim = externalIdentity.Result.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Email);
var lastNameClaim = externalIdentity.Result.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Surname);
var givenNameClaim = externalIdentity.Result.Claims.FirstOrDefault(c => c.Type == ClaimTypes.GivenName);
//var DOBClaim = externalIdentity.Result.Claims.FirstOrDefault(c => c.Type == ClaimTypes.DateOfBirth);
//var genderClaim = externalIdentity.Result.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Gender);
//var LocClaim = externalIdentity.Result.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Locality);
//var countryClaim = externalIdentity.Result.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Country);
//var mobileClaim = externalIdentity.Result.Claims.FirstOrDefault(c => c.Type == ClaimTypes.);
var accesstoken = externalIdentity.Result.Claims.FirstOrDefault(c => c.Type.Equals("urn:tokens:google:accesstoken"));
var Photo = externalIdentity.Result.Claims.FirstOrDefault(c => c.Type.Equals("urn:tokens:google:accesstoken"));
var userid = loginInfo.ExternalIdentity.GetUserId();
var email = emailClaim.Value;
var firstName = givenNameClaim.Value;
var lastname = lastNameClaim.Value;
var token = accesstoken.Value;
Session["FullName"] = firstName + " " +lastname;
Session["FName"] = firstName;
Session["LName"]= lastname;
Session["Email"] = email;
Session["GoogleAccessToken"] = token;
Session["UserID"] = userid;
//get access token to use in profile image request
// var accessToken = loginInfo.ExternalIdentity.Claims.Where(c => c.Type.Equals("urn:google:accesstoken")).Select(c => c.Value).FirstOrDefault();
Uri apiRequestUri = new Uri("https://www.googleapis.com/oauth2/v2/userinfo?access_token=" + token);
//request profile image
using (var webClient = new System.Net.WebClient())
{
var json = webClient.DownloadString(apiRequestUri);
dynamic result_pic = JsonConvert.DeserializeObject(json);
Session["PhotoURL"] = result_pic.picture.Value;
}
}
// Sign in the user with this external login provider if the user already has a login
var result = await SignInManager.ExternalSignInAsync(loginInfo, isPersistent: false);
switch (result)
{
case SignInStatus.Success:
{
Session["ProviderKey"] = loginInfo.Login.ProviderKey;
Session["Provider"] = loginInfo.Login.LoginProvider;
return RedirectToLocal(returnUrl);
}
case SignInStatus.LockedOut:
return View("Lockout");
case SignInStatus.RequiresVerification:
return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = false });
case SignInStatus.Failure:
default:
// If the user does not have an account, then prompt the user to create an account
ViewBag.ReturnUrl = returnUrl;
ViewBag.LoginProvider = loginInfo.Login.LoginProvider;
return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { Email = loginInfo.Email });
}
}
问题是,ExternalLoginCallback没有被调用,并且登录过程不完整。当我使用开发人员工具深入挖掘请求/响应时,我发现响应是状态&#39; 302 Found&#39;。
支持代码如下,
internal class ChallengeResult : HttpUnauthorizedResult
{
public ChallengeResult(string provider, string redirectUri)
: this(provider, redirectUri, null)
{
}
public ChallengeResult(string provider, string redirectUri, string userId)
{
LoginProvider = provider;
RedirectUri = redirectUri;
UserId = userId;
}
public string LoginProvider { get; set; }
public string RedirectUri { get; set; }
public string UserId { get; set; }
ChallengeResult()方法调用ExecuteResult(下面),帖子我得到了Google错误:400-redirect_uri_mismatch
public override void ExecuteResult(ControllerContext context)
{
var properties = new AuthenticationProperties { RedirectUri = RedirectUri };
if (UserId != null)
{
properties.Dictionary[XsrfKey] = UserId;
}
context.HttpContext.GetOwinContext().Authentication.Challenge(properties, LoginProvider);
}
}
我检查了这些帖子并相应地修改了代码,但问题仍然存在。 Why MVC 5 Owin Oauth is not hitting /Account/ExternalLoginCallback action