在新用户调用后,开箱即用的ASP.NET WEB API oAuth实现:
GET api/Account/ExternalLogins?returnUrl=%2F&generateState=true
用户被重定向到外部登录(在我的情况下是Facebook),导致他们用于注册的令牌(开箱即用的代码)
// POST api/Account/RegisterExternal
[OverrideAuthentication]
[HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
[Route("RegisterExternal")]
public async Task<IHttpActionResult> RegisterExternal([FromBody]RegisterExternalBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
ExternalLoginData externalLogin = ExternalLoginData.FromIdentity(User.Identity as ClaimsIdentity);
if (externalLogin == null)
{
return InternalServerError();
}
IdentityUser user = new IdentityUser
{
UserName = model.UserName
};
user.Logins.Add(new IdentityUserLogin
{
LoginProvider = externalLogin.LoginProvider,
ProviderKey = externalLogin.ProviderKey
});
IdentityResult result = await UserManager.CreateAsync(user);
IHttpActionResult errorResult = GetErrorResult(result);
if (errorResult != null)
{
return errorResult;
}
return Ok();
}
在RegisterExternal期间我想使用Facebook上的数据填充另一个数据库(名字,姓氏,电子邮件,朋友,分机......)
我在注册时获得的持票人令牌可以不简单地这样称呼:
var accessToken = "token from header";
var client = new FacebookClient(accessToken);
所以根据我的理解,我需要修改Startup.Auth并声明这些数据,因为我已经通过添加:
var facebookProvider = new FacebookAuthenticationProvider()
{
OnAuthenticated = (context) =>
{
// Add the email id to the claim
context.Identity.AddClaim(new Claim(ClaimTypes.Email, context.Email));
return Task.FromResult(0);
}
};
var options = new FacebookAuthenticationOptions()
{
AppId = "xxxxxxxxxxxxxxxxx",
AppSecret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
Provider = facebookProvider
};
options.Scope.Add("email");
options.Scope.Add("user_friends");
options.Scope.Add("public_profile");
app.UseFacebookAuthentication(options);
但是我如何在RegisterExternal方法中获取数据?
答案 0 :(得分:3)
我有同样的问题(我认为) - 问题是FB OAuth基础架构只填充基本数据而我想要更多。
在深入研究ASP.NET身份的源代码后,我发现了以下内容:
app.UseFacebookAuthentication(new FacebookAuthenticationOptions
{
AppId = "",
AppSecret = "",
Scope = { "public_profile", "email", "user_birthday", "user_location" },
Provider = new FacebookAuthProvider(),
UserInformationEndpoint = "https://graph.facebook.com/v2.5/me?fields=id,name,email,first_name,last_name,location,birthday,picture",
});
这里的重要部分是自定义提供者:
private class FacebookAuthProvider : FacebookAuthenticationProvider
{
/// <summary>
/// Invoked whenever Facebook succesfully authenticates a user
/// </summary>
/// <param name="context">Contains information about the login session as well as the user <see cref="T:System.Security.Claims.ClaimsIdentity" />.</param>
/// <returns>A <see cref="T:System.Threading.Tasks.Task" /> representing the completed operation.</returns>
public override Task Authenticated(FacebookAuthenticatedContext context)
{
TryParseProperty(context, "first_name", Claims.FirstName);
TryParseProperty(context, "last_name", Claims.LastName);
TryParseProperty(context, "picture.data.url", Claims.PhotoUrl);
return base.Authenticated(context);
}
private void TryParseProperty(FacebookAuthenticatedContext context, string name, string targetName)
{
var value = context.User.SelectToken(name);
if (value != null)
{
context.Identity.AddClaim(targetName, value.ToString());
}
}
}
这基本上将所有数据都放在索赔中,并且可以在任何其他地方以相同的方式检索。
答案 1 :(得分:2)
外部提供商(在本例中为Facebook)将填充声明,并且可以在LoginInfo中的回调方法中访问这些声明。
以下是阅读Facebook Access令牌的代码:
var accessToken = loginInfo.ExternalIdentity.Claims.FirstOrDefault(x => x.Type == Constants.FacebookAccessToken).Value;
如果您在那里设置断点,您将能够看到Facebook返回的其他内容。
答案 2 :(得分:1)
John Mc真的指出了我正确的方向,这是一个更完整的解决方案。
// POST api/Account/RegisterExternalToken
[OverrideAuthentication]
[HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
[Route("RegisterExternalToken")]
public async Task<IHttpActionResult> RegisterExternalToken()
{
ExternalLoginData externalLogin = ExternalLoginData.FromIdentity(User.Identity as ClaimsIdentity);
if (externalLogin == null)
{
return InternalServerError();
}
var facebookToken = externalLogin.Token;
然后在声明中(这是关键部分)正如约翰所指出的那样:
private class ExternalLoginData
{
public string LoginProvider { get; set; }
public string ProviderKey { get; set; }
public string UserName { get; set; }
public string Token { get; set; }
public IList<Claim> GetClaims()
{
IList<Claim> claims = new List<Claim>();
claims.Add(new Claim(ClaimTypes.NameIdentifier, ProviderKey, null, LoginProvider));
if (UserName != null)
{
claims.Add(new Claim(ClaimTypes.Name, UserName, null, LoginProvider));
}
if (Token != null)
{
claims.Add(new Claim("FacebookAccessToken", Token, null, LoginProvider));
}
return claims;
}
public static ExternalLoginData FromIdentity(ClaimsIdentity identity)
{
if (identity == null)
{
return null;
}
Claim providerKeyClaim = identity.FindFirst(ClaimTypes.NameIdentifier);
if (providerKeyClaim == null || String.IsNullOrEmpty(providerKeyClaim.Issuer)
|| String.IsNullOrEmpty(providerKeyClaim.Value))
{
return null;
}
if (providerKeyClaim.Issuer == ClaimsIdentity.DefaultIssuer)
{
return null;
}
return new ExternalLoginData
{
LoginProvider = providerKeyClaim.Issuer,
ProviderKey = providerKeyClaim.Value,
UserName = identity.FindFirstValue(ClaimTypes.Name),
Token = identity.Claims.FirstOrDefault(x => x.Type.Contains("FacebookAccessToken")).Value
};
}
}