我正在尝试构建一个API(使用ASP.NET WebApi),该API将由学校项目的本机移动应用程序使用。 (我不关心/开发移动应用程序,这个责任落在另一个成员身上) 我正处于需要实现基于令牌的Facebook登录的地步。有很多教程可用于如何为基于浏览器的应用程序实现此功能(这是非常直接的,大部分都是内置的),但我不认为我会遵循如何使用本机应用程序。我不明白重定向是如何工作的?
根据这个link,我的服务器无需专门处理任何事情。我不认为我明白这是如何工作的?如何处理来自Facebook的令牌?
此外,我应该实现令牌处理的哪个部分,我无法找到WebApi外部登录身份验证的良好文档。
无论如何,如果有人能指出我发生的令牌交换的确切流程以及ASP.NET默认实现的内容,那将是非常有用的。
此外,对我来说最大的困惑是我不明白Facebook将返回的令牌将如何处理。
如果这是我应该弄明白的话,我很抱歉。我做了很多研究,发现自己陷入(相关和无关)信息中。我认为我甚至不知道如何搜索我需要的信息。
我读过一些链接:
Claims And Token Based Authentication (ASP.NET Web API)
Token Based Authentication using ASP.NET Web API 2, Owin, and Identity
ASP.NET Web API 2 external logins with Facebook and Google in AngularJS app
答案 0 :(得分:11)
对于我正在处理的应用程序,我必须做同样的事情。我也很难找到有关它的信息。似乎我发现的一切都接近我所需要的,但不完全是解决方案。我最终从一堆不同的博客文章,文章等中汲取了点点滴滴,并将它们放在一起以使其发挥作用。
我记得你发布的两个链接"声明和基于令牌的身份验证"和#34; ASP.NET Web API 2在AngularJS应用程序中使用Facebook和Google进行外部登录"作为那些有用信息的人。
我不能给你一个全面的答案,因为我不记得我必须做的一切,我甚至不理解我当时所做的一切,但我可以给你一般的想法。你走在正确的轨道上。
基本上我最终使用Facebook授予的令牌来确认他们已登录到他们的Facebook帐户,根据他们的Facebook用户ID创建用户,并授予他们可用于访问我的API的我自己的持票人令牌。
流程看起来像这样:
最终有很多自定义代码用于实现ASP.NET身份的OAuth内容,而您包含的那些链接会向您展示其中的一些内容。希望这些信息对你有所帮助,抱歉,我无法提供更多帮助。
答案 1 :(得分:0)
我关注了this article。流程基本上就是这个
老实说,我不知道这种方法是否合法...
操作按钮的代码应重定向到:
public async Task<IEnumerable<ExternalLoginDto>> GetExternalLogins(string returnUrl, bool generateState = false)
{
IEnumerable<AuthenticationScheme> loginProviders = await SignInManager.GetExternalAuthenticationSchemesAsync();
var logins = new List<ExternalLoginDto>();
string state;
if (generateState)
{
const int strengthInBits = 256;
state = RandomOAuthStateGenerator.Generate(strengthInBits);
}
else
{
state = null;
}
foreach (AuthenticationScheme authenticationScheme in loginProviders)
{
var routeValues = new
{
provider = authenticationScheme.Name,
response_type = "token",
client_id = Configuration["Jwt:Issuer"],
redirect_uri = $"{Request.Scheme}//{Request.Host}{returnUrl}",
state = state
};
var login = new ExternalLoginDto
{
Name = authenticationScheme.DisplayName,
Url = Url.RouteUrl("ExternalLogin", routeValues),
State = state
};
logins.Add(login);
}
return logins;
}
回调操作的代码:
[Authorize(AuthenticationSchemes = "Identity.External")]
[Route("ExternalLogin", Name = "ExternalLogin")]
public async Task<IActionResult> GetExternalLogin(string provider, string state = null, string client_id = null, string error = null)
{
if (error != null)
{
ThrowBadRequest(error);
}
if (!User.Identity.IsAuthenticated)
{
return new ChallengeResult(provider);
}
string providerKey = User.FindFirstValue(ClaimTypes.NameIdentifier);
var externalLoginInfo = new ExternalLoginInfo(User, User.Identity.AuthenticationType, providerKey, User.Identity.AuthenticationType);
if (externalLoginInfo.LoginProvider != provider)
{
await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
return new ChallengeResult(provider);
}
var userLoginInfo = new UserLoginInfo(externalLoginInfo.LoginProvider, externalLoginInfo.ProviderKey, externalLoginInfo.ProviderDisplayName);
User user = await UserManager.FindByLoginAsync(externalLoginInfo.LoginProvider, externalLoginInfo.ProviderKey);
if (client_id != Configuration["Jwt:Issuer"])
{
return Redirect($"/#error=invalid_client_id_{client_id}");
}
if (user != null)
{
return await LoginWithLocalUser(user, state);
}
else
{
string email = null;
string firstName = null;
string lastName = null;
IEnumerable<Claim> claims = externalLoginInfo.Principal.Claims;
if (externalLoginInfo.LoginProvider == "Google")
{
email = claims.FirstOrDefault(c => c.Type == ClaimTypes.Email)?.Value;
firstName = claims.FirstOrDefault(c => c.Type == ClaimTypes.GivenName)?.Value;
lastName = claims.FirstOrDefault(c => c.Type == ClaimTypes.Surname)?.Value;
}
else if (externalLoginInfo.LoginProvider == "Facebook")
{
email = claims.FirstOrDefault(c => c.Type == ClaimTypes.Email)?.Value;
string[] nameParts = claims.First(c => c.Type == ClaimTypes.Name)?.Value.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
firstName = nameParts?.First();
lastName = nameParts?.Last();
}
//some fallback just in case
firstName ??= externalLoginInfo.Principal.Identity.Name;
lastName ??= externalLoginInfo.Principal.Identity.Name;
user = new User
{
UserName = email,
Email = email,
FirstName = firstName,
LastName = lastName,
EmailConfirmed = true //if the user logs in with Facebook consider the e-mail confirmed
};
IdentityResult userCreationResult = await UserManager.CreateAsync(user);
if (userCreationResult.Succeeded)
{
userCreationResult = await UserManager.AddLoginAsync(user, userLoginInfo);
if (userCreationResult.Succeeded)
{
return await LoginWithLocalUser(user, state);
}
}
string identityErrrors = String.Join(" ", userCreationResult.Errors.Select(ie => ie.Description));
Logger.LogWarning($"Error registering user with external login. Email:{email}, Errors:" + Environment.NewLine + identityErrrors);
return Redirect($"/#error={identityErrrors}");
}
}
private async Task<RedirectResult> LoginWithLocalUser(User user, string state)
{
await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
DateTime expirationDate = DateTime.UtcNow.AddDays(365);
string token = user.GenerateJwtToken(Configuration["Jwt:Key"], Configuration["Jwt:Issuer"], expirationDate);
return Redirect($"/#access_token={token}&token_type=bearer&expires_in={(int)(expirationDate - DateTime.UtcNow).TotalSeconds}&state={state}");
}