通过社交网络进行OWIN OAuth2身份验证

时间:2024-03-24 08:51:51


下载OwinAuthenticationExample.zip - 420.6 KB

介绍

        在本文中,您可以找到有关如何通过社交网络(Facebook,Google和Microsoft)对用户进行身份验证的代码,演示和说明示例。如何提取有关用户的其他信息,如头像,电子邮件和全名。
通过社交网络进行OWIN OAuth2身份验证通过社交网络进行OWIN OAuth2身份验证
通过社交网络进行OWIN OAuth2身份验证

基本概念

Owin中间件

        该Owin中间件模块负责处理与外部供应商的身份验证(如Facebook,谷歌等)的认证(authentication),并通过一个cookie建立应用会话。在所有后续调用中,应用程序cookie中间件提取传入应用程序cookie的内容并设置当前上下文的声明标识(claims identity)。

什么是令牌(token)?

        令牌是表示System.Security.Claims加密列表的字符串值。您可以使用任何您喜欢的声明。我的应用程序在项目中使用了自己定义的声明列表。我们称之为应用程序声明(Application Claims)。
        应用程序声明(Application Claims)是由OWIN加密到已颁发令牌中的明确定义的声明列表。每次服务收到令牌时,它都会尝试使用其IIS机器**解密其为声明列表并填充User.Identity对象。
        要确定它是外部承载令牌(External Bearer token)还是本地令牌,它会检查声明的颁发者(Issuer)字段。对于本地令牌来说,它必须始终是ClaimsIdentity.DefaultIssuer。
        注意,对于使用IIS机器**加密OWIN,这就是为什么必须应用一些自定义解决方案来跨多个WEB服务使用相同的令牌。
以下是我构建应用程序声明列表的方法:

private static ClaimsIdentity CreateIdentity(ClaimsMapper claimsMapper, string authenticationType)
{
	IList<claim> claims = new List<claim>();

	claims.Add(new Claim(ClaimTypes.NameIdentifier, claimsMapper.Id, null, claimsMapper.Issuer, claimsMapper.OriginalIssuer));
	claims.Add(new Claim(ClaimTypes.Email, claimsMapper.Email, null, claimsMapper.Issuer, claimsMapper.OriginalIssuer));
	claims.Add(new Claim(ClaimTypes.GivenName, claimsMapper.FullName, null, claimsMapper.Issuer, claimsMapper.OriginalIssuer));
	claims.Add(new Claim(ClaimTypes.Sid, claimsMapper.Sid, null, claimsMapper.Issuer, claimsMapper.OriginalIssuer));
	claims.Add(new Claim(ClaimTypes.Version, claimsMapper.Version, null, claimsMapper.Issuer, claimsMapper.OriginalIssuer));
	claims.Add(new Claim(ClaimTypeIsVerified, claimsMapper.IsVerified, null, claimsMapper.Issuer, claimsMapper.OriginalIssuer));
	claims.Add(new Claim(ClaimTypeAvatarUrl, claimsMapper.AvatarUrl, null, claimsMapper.Issuer, claimsMapper.OriginalIssuer));

	return new ClaimsIdentity(claims, authenticationType);
}

        所以,我总是可以从我的WEB服务发出的任何令牌中获取所有这些信息。ClaimsMapper是一种抽象策略,其知道如何将不同的数据模型映射到我的声明列表。

认证流程

OAuth2身份认证

应用程序如何从Facebook,Google等获取用户信息?
从外部提供商(Facebook,Google等)收到的有关用户的所有信息都在外部cookie中加密。
以下是应用程序与外部提供程序之间的通信流程的说明:
通过社交网络进行OWIN OAuth2身份验证

// GET api/Account/ExternalLogin
[AllowAnonymous]
[HostAuthentication(DefaultAuthenticationTypes.ExternalCookie)] //authenticated by external provider
[HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)] //refresh token support
[Route("externalLogin", Name = "externalLogin")]
public async Task<ihttpactionresult> GetExternalLogin(string provider, string error = null)
{
	if (error != null)
	{
		return Redirect(Url.Content("~/") + "#error=" + Uri.EscapeDataString(error));
	}

	ExternalLoginProvider loginProvider;
	if (!Enum.TryParse<externalloginprovider>(provider, ignoreCase: true, result: out loginProvider) ||
		loginProvider == ExternalLoginProvider.None)
	{
		//Unsupported login provider
		return InternalServerError();
	}

	if (!User.Identity.IsAuthenticated)
	{
		return new ChallengeResult(loginProvider, this);
	}

	ExternalLoginModel externalLogin = ExternalLoginModel.FromIdentity(User.Identity as ClaimsIdentity);

	if (externalLogin == null)
	{
		return InternalServerError();
	}

	if (externalLogin.Provider != loginProvider)
	{
		Request.GetOwinContext().Authentication.SignOut(
			DefaultAuthenticationTypes.ExternalCookie,
			OAuthDefaults.AuthenticationType,
			CookieAuthenticationDefaults.AuthenticationType);
		return new ChallengeResult(loginProvider, this);
	}

	User user = await this.UserProvider.FindAsync(externalLogin.Provider, externalLogin.ProviderKey);
	if (user != null)
	{
		OwinHelper.SingIn(Request.GetOwinContext(), user, externalLogin);
	}
	else
	{
		OwinHelper.SingIn(Request.GetOwinContext(), externalLogin);
	}

	return Ok();
}
</externalloginprovider></ihttpactionresult>

Facebook用户的数据提取:

public class FacebookOAuthProvider : FacebookAuthenticationProvider
{
	private const string ApiBaseUrl = "https://graph.facebook.com";

	public override Task Authenticated(FacebookAuthenticatedContext context)
	{
		string avatarUrl = GetAvatarUrl(context.User.GetValue("id").ToString(), 240);
		context.Identity.AddClaim(
			new Claim(OwinHelper.ClaimTypeAvatarUrl, avatarUrl));

		return base.Authenticated(context);
	}

	public static string GetAvatarUrl(string facebookUserId, int size)
	{
		return string.Format("{0}/{1}/picture?width={2}&height={2}",
			ApiBaseUrl,
			facebookUserId,
			size);
	}
}

Google用户的数据提取:

public class GoogleOAuthProvider : GoogleOAuth2AuthenticationProvider
{
	public override Task Authenticated(GoogleOAuth2AuthenticatedContext context)
	{
		string avatarUrl = context.User
			.SelectToken("image.url")
			.ToString()
			.Replace("sz=50", "sz=240");

		context.Identity.AddClaim(
			new Claim(OwinHelper.ClaimTypeAvatarUrl, avatarUrl));

		return base.Authenticated(context);
	}
}

Microsoft用户的数据提取:

public class MicrosoftOAuthProvider : MicrosoftAccountAuthenticationProvider
{
	public override void ApplyRedirect(MicrosoftAccountApplyRedirectContext context)
	{
		context = new MicrosoftAccountApplyRedirectContext(
			context.OwinContext,
			context.Options,
			context.Properties,
			context.RedirectUri + "&display=touch"); //Mobile devices support

		base.ApplyRedirect(context);
	}

	public override Task Authenticated(MicrosoftAccountAuthenticatedContext context)
	{
		string avatarUrl = string.Format("https://apis.live.net/v5.0/{0}/picture",
						context.User.GetValue("id").ToString());

		context.Identity.AddClaim(
			new Claim(OwinHelper.ClaimTypeAvatarUrl, avatarUrl));

		return base.Authenticated(context);
	}
}

令牌发行

一旦用户通过身份认证,应用程序就会有三个不同的流程来发布令牌(步骤10中的详细视图):

  1. 一个新的用户是通过认证的外部供应商:
    通过社交网络进行OWIN OAuth2身份验证
    一个外部承载令牌发出后,用户可以使用此令牌的应用程序注册,然后再重新认证,获取新的令牌(本地承载)。
public class NotRegisteredExternal : ClaimsMapper
{
	public NotRegisteredExternal(ExternalLoginModel extLogin)
	{
		this.Id = string.Empty;
		this.Email = extLogin.Email ?? string.Empty;
		this.FullName = extLogin.FullName ?? string.Empty;
		this.AvatarUrl = extLogin.AvatarUrl ?? string.Empty;
		this.Sid = extLogin.ProviderKey;
		this.Version = string.Empty;
		this.IsVerified = false.ToString();
		this.Issuer = extLogin.Provider.ToString();
		this.OriginalIssuer = this.Issuer;
	}
}
  1. 一个现有的用户是通过认证的外部供应商:
    通过社交网络进行OWIN OAuth2身份验证
public class RegisteredExternal : ClaimsMapper
{
	public RegisteredExternal(User user, ExternalLoginModel extLogin)
	{
		this.Id = user.Id.ToString();
		this.Email = user.Email;
		this.FullName = user.FullName ?? string.Empty;
		this.AvatarUrl = UserProvider.GetAvatarUrl(user);
		this.Sid = extLogin.ProviderKey;
		this.Version = this.GetVersion(user.TimeStamp);
		this.IsVerified = user.IsVerified.ToString();
		this.Issuer = ClaimsIdentity.DefaultIssuer;
		this.OriginalIssuer = extLogin.Provider.ToString();
	}
}
  1. 一个现有用户通过认证登录/密码:
    通过社交网络进行OWIN OAuth2身份验证
public class RegisteredLocal : ClaimsMapper
{
	public RegisteredLocal(User user)
	{
		this.Id = user.Id.ToString();
		this.Email = user.Email;
		this.FullName = user.FullName ?? string.Empty;
		this.AvatarUrl = UserProvider.GetAvatarUrl(user);
		this.Sid = string.Empty;
		this.Version = this.GetVersion(user.TimeStamp);
		this.IsVerified = user.IsVerified.ToString();
		this.Issuer = ClaimsIdentity.DefaultIssuer;
		this.OriginalIssuer = ClaimsIdentity.DefaultIssuer;
	}
}

向外部提供商注册您的应用程序

Facebook配置

  1. 导航到Facebook开发者页面并输入您的Facebook凭据登录;
  2. 如果您尚未注册为Facebook开发人员,请单击“注册为开发人员”并按照说明进行注册;
  3. 在我的应用程序选项卡下,单击+添加新应用程序按钮:
    通过社交网络进行OWIN OAuth2身份验证
  4. 选择一个网站作为应用程序平台:
    通过社交网络进行OWIN OAuth2身份验证
  5. 输入应用程序名称和类别,然后单击“创建应用程序”。
    这在Facebook上必须是独一无二的。该应用程序命名空间(App Namespace)为您的应用程序将用于访问进行身份认证的Facebook应用程序的URL的一部分(例如,https://apps .facebook .com/{App命名空间})。如果未指定应用程序命名空间(App Namespace),则应用程序ID将用于URL。该应用程序ID(App ID)是一个长期的系统生成的编号,你将在下一步看到。
  6. 在页面的基本设置部分:
  • 输入联系电邮 ;
  • 输入将向Facebook发送请求的站点URL。
    通过社交网络进行OWIN OAuth2身份验证
    请注意,只有您才能使用已注册的电子邮件别名进行身份认证。其他用户和测试帐户将无法注册。
    您可以授予测试用户对“角色”菜单下的应用程序的访问权限。
    对于所有其他Facebook帐户,您的申请必须由Facebook 批准。如需进一步说明,请查看状态和复查(Status & Review )菜单。
  1. 要为您的应用禁用沙盒模式,请转到左侧的状态和复查(Status & Review )菜单,然后选择是:
    通过社交网络进行OWIN OAuth2身份验证

Google配置

  1. 导航到Google Developers Console ;
  2. 单击“创建项目”按钮并输入项目名称和ID(您可以使用默认值)。几秒钟后,将创建新项目,浏览器将显示新项目页面;
  3. 在左侧选项卡中,单击“API和身份认证”,然后单击同意屏幕(Consent screen):
  • 输入电邮地址 ;
  • 输入产品名称:
    通过社交网络进行OWIN OAuth2身份验证
  1. 在左侧选项卡中,单击“API和身份认证”,然后单击“API”:
  • 启用Google+ API以支持用户的头像访问权限:
    通过社交网络进行OWIN OAuth2身份验证
  1. 在左侧选项卡中,单击“API和身份认证”,然后单击“凭据”。
  2. 点击OAuth下的新建客户ID:
  • 在“创建客户端ID”对话框中,保留应用程序类型的默认Web应用程序;
  • 将授权的JavaScript源设置为服务的SSL URL,例如:https://supperslonic.com/ ;
  • 将授权重定向URI设置为:https://supperslonic.com/ signin-google。
    通过社交网络进行OWIN OAuth2身份验证
  1. 将AppId和App Secret复制并粘贴到Google 的Credentials.resx文件中。

Microsoft配置

  1. 导航到Microsoft Developer Account ;
  2. 按创建应用程序引用;
  3. 在基本信息中输入有效的应用程序名称服务的网址:
    通过社交网络进行OWIN OAuth2身份验证
  4. 在API设置中,选择它是移动应用程序并输入有效的重定向URL:
  • 请注意将signin-microsoft添加到重定向URL。
    通过社交网络进行OWIN OAuth2身份验证
  1. 在应用程序设置中,将AppId和App Secret复制并粘贴到Microsoft 的Credentials.resx文件中。

原文地址:https://www.codeproject.com/Articles/873598/OWIN-OAuth-authentication-via-Social-networks