可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I'm trying to use the new MVC5 framework in VS 2013 preview.
The membership authentication framework has been overhauled and replaced with OWin
.
In particular, I turned on external authentication provider Google auth.
It was very simple to do.
Simply uncomment this line: app.UseGoogleAuthentication();
in the Startup.Auth.cs file in the App_Start directory of the new default MVC project.
So, I want access the "Extra Data" that comes from the Authentication provider, such as a url to the user's avatar to display in my application.
Under the older OAuth implementation against asp.net Membership provider, there was a way to capture this using this ExtraData dictionary found here: ProviderDetail.ExtraData Property.
I can't find much documentation about how OAuth and OWin work together and how to access this extra data.
Can anyone enlighten me?
回答1:
Recently I had to get access to Google profile's picture as well and here is how I solve it...
If you just enable the code app.UseGoogleAuthentication();
in the Startup.Auth.cs file it's not enough because in this case Google doesn't return any information about profile's picture at all (or I didn't figure out how to get it).
What you really need is using OAuth2 integration instead of Open ID that enabled by default. And here is how I did it...
First of all you have to register your app on Google side and get "Client ID" and "Client secret". As soon as this done you can go further (you will need it later). Detailed information how to do this here.
Replace app.UseGoogleAuthentication();
with
var googleOAuth2AuthenticationOptions = new GoogleOAuth2AuthenticationOptions
{
ClientId = "<<CLIENT ID FROM GOOGLE>>",
ClientSecret = "<<CLIENT SECRET FROM GOOGLE>>",
CallbackPath = new PathString("/Account/ExternalGoogleLoginCallback"),
Provider = new GoogleOAuth2AuthenticationProvider() {
OnAuthenticated = async context =>
{
context.Identity.AddClaim(new Claim("picture", context.User.GetValue("picture").ToString()));
context.Identity.AddClaim(new Claim("profile", context.User.GetValue("profile").ToString()));
}
}
};
googleOAuth2AuthenticationOptions.Scope.Add("email");
app.UseGoogleAuthentication(googleOAuth2AuthenticationOptions);
After that you can use the code to get access to the profile's picture URL same way as for any other properties
var externalIdentity = HttpContext.GetOwinContext().Authentication.GetExternalIdentityAsync(DefaultAuthenticationTypes.ExternalCookie);
var pictureClaim = externalIdentity.Result.Claims.FirstOrDefault(c => c.Type.Equals("picture"));
var pictureUrl = pictureClaim.Value;
回答2:
With RTW version of asp.net identity the following code in ExternalLoginCallback
does that for me.
var externalIdentity = await HttpContext.GetOwinContext().Authentication
.GetExternalIdentityAsync(DefaultAuthenticationTypes.ExternalCookie);
var displayName = externalIdentity.Name;
var email = externalIdentity.FindFirstValue(ClaimTypes.Email);
回答3:
Using Alex Wheat's answer, I came up with a solution to retrive the google+ profile, gender and e-mail using Google Authentication.
Startup.Auth.cs:
var googleOptions = new GoogleOAuth2AuthenticationOptions()
{
ClientId = "<<client id - google>>",
ClientSecret = "<<secret for your app>>",
Provider = new GoogleOAuth2AuthenticationProvider()
{
OnAuthenticated = context =>
{
var userDetail = context.User;
context.Identity.AddClaim(new Claim(ClaimTypes.Name,context.Identity.FindFirstValue(ClaimTypes.Name)));
context.Identity.AddClaim(new Claim(ClaimTypes.Email,context.Identity.FindFirstValue(ClaimTypes.Email)));
var gender = userDetail.Value<string>("gender");
context.Identity.AddClaim(new Claim(ClaimTypes.Gender, gender));
var picture = userDetail.Value<string>("picture");
context.Identity.AddClaim(new Claim("picture", picture));
return Task.FromResult(0);
},
},
};
googleOptions.Scope.Add("https://www.googleapis.com/auth/plus.login");
googleOptions.Scope.Add("https://www.googleapis.com/auth/userinfo.email");
app.UseGoogleAuthentication(googleOptions);
To get access to extended profile data, you should add two scopes to the request - plus.login and userinfo.email. If you only add the plus.login scope, you won't be able to see the user's e-mail. If you use ASP.NET MVC5's default template to authenticate, it will only show the user's e-mail, Name, Surname and google+ profile address. Using the way shown here, you'll have access also to the user's picture link.
The context.User property carries a JSON serialization of the user's data sent across the wire and have useful methods to let the user find a property by its key.
To learn more about login scopes concept, please take a look at:
https://developers.google.com/+/api/oauth#login-scopes
回答4:
The following post details on how you can get extra data from the social providers
http://blogs.msdn.com/b/webdev/archive/2013/10/16/get-more-information-from-social-providers-used-in-the-vs-2013-project-templates.aspx
回答5:
The following works for me for facebook:
StartupAuth.cs:
var facebookAuthenticationOptions = new FacebookAuthenticationOptions()
{
AppId = "x",
AppSecret = "y"
};
facebookAuthenticationOptions.Scope.Add("email");
app.UseFacebookAuthentication(facebookAuthenticationOptions);
ExternalLoginCallback method:
var externalIdentity = HttpContext.GetOwinContext().Authentication.GetExternalIdentityAsync(DefaultAuthenticationTypes.ExternalCookie);
var emailClaim = externalIdentity.Result.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Email);
var email = emailClaim.Value;
And for Google:
StartupAuth.cs
app.UseGoogleAuthentication();
ExternalLoginCallback method (same as for facebook):
var externalIdentity = HttpContext.GetOwinContext().Authentication.GetExternalIdentityAsync(DefaultAuthenticationTypes.ExternalCookie);
var emailClaim = externalIdentity.Result.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Email);
var email = emailClaim.Value;
If I set a breakpoint here:
var email = emailClaim.Value;
I see the email address for both facebook and Google in the debugger.
Update: See this post instead for proper and complete solution; Getting the email from external providers Google and Facebook during account association step in a default MVC5 app
回答6:
So unfortunately this is not super straightforward, one way you can do this is to hook the GoogleProvider Authenticated event and add a custom claim to the Claims Identity with the avatar:
public class MyGoogleProvider : GoogleAuthenticationProvider {
public override Task Authenticated(GoogleAuthenticatedContext context) {
context.Identity.AddClaim(new Claim("avatarClaim", "<fetch avatar url here>"));
return base.Authenticated(context);
}
}
app.UseGoogleAuthentication(new GoogleAuthenticationOptions() { Provider = new MyGoogleProvider() });
Then inside of your AccountController, when the external identity is extracted, you can take this avatar claim and store it into your user object for use later.
回答7:
Here is a good answer from AndrewPolland. Work for me. He use the new oauth access token to retrieve the user info after login. From here Deepak Goswami explain how to use this api call.