title: "AspNetCore3" date: 2020 03 26T13:23:27+08:00 draft: false 系列文章目錄 "AspNetCore3.1_Secutiry源碼解析_1_目錄" "AspNetCore3.1_Secutiry源碼解析_2_Authenticatio ...
title: "AspNetCore3"
date: 2020-03-26T13:23:27+08:00
draft: false
系列文章目錄
- AspNetCore3.1_Secutiry源碼解析_1_目錄
- AspNetCore3.1_Secutiry源碼解析_2_Authentication_核心流程
- AspNetCore3.1_Secutiry源碼解析_3_Authentication_Cookies
- AspNetCore3.1_Secutiry源碼解析_4_Authentication_JwtBear
- AspNetCore3.1_Secutiry源碼解析_5_Authentication_OAuth
- AspNetCore3.1_Secutiry源碼解析_6_Authentication_OpenIdConnect
- AspNetCore3.1_Secutiry源碼解析_7_Authentication_其他
- AspNetCore3.1_Secutiry源碼解析_8_Authorization_核心項目
- AspNetCore3.1_Secutiry源碼解析_9_Authorization_Policy
簡介
Secutiry的認證目錄還有這些項目,基本都是具體的OAuth2.0服務商或者其他用的比較少的認證架構,簡單看一下,瞭解一下。
- Microsoft.AspNetCore.Authentication.Certificate
- Microsoft.AspNetCore.Authentication.Facebook
- Microsoft.AspNetCore.Authentication.Google
- Microsoft.AspNetCore.Authentication.MicrosoftAccount
- Microsoft.AspNetCore.Authentication.Negotiate
- Microsoft.AspNetCore.Authentication.Twitter
- Microsoft.AspNetCore.Authentication.WsFederation
OAuth2.0服務商
Facebook, Google,MicrosoftAccount這幾個都可以歸為一類,都是OAuth2.0的服務商。國內用的比較多的是QQ,Weixin。我們看一下Facebook的代碼,其他的原理都是大同小異的,根據不同廠商的差異稍作調整就可以了。
Twitter似乎是用的OAuth1.0協議。
依賴註入
配置類: FacebookOptions,處理器類:FacebookHandler
public static class FacebookAuthenticationOptionsExtensions
{
public static AuthenticationBuilder AddFacebook(this AuthenticationBuilder builder)
=> builder.AddFacebook(FacebookDefaults.AuthenticationScheme, _ => { });
public static AuthenticationBuilder AddFacebook(this AuthenticationBuilder builder, Action<FacebookOptions> configureOptions)
=> builder.AddFacebook(FacebookDefaults.AuthenticationScheme, configureOptions);
public static AuthenticationBuilder AddFacebook(this AuthenticationBuilder builder, string authenticationScheme, Action<FacebookOptions> configureOptions)
=> builder.AddFacebook(authenticationScheme, FacebookDefaults.DisplayName, configureOptions);
public static AuthenticationBuilder AddFacebook(this AuthenticationBuilder builder, string authenticationScheme, string displayName, Action<FacebookOptions> configureOptions)
=> builder.AddOAuth<FacebookOptions, FacebookHandler>(authenticationScheme, displayName, configureOptions);
}
配置類 - FacebookOptions
配置類繼承自OAuthOptions,構造函數根據Facebook做了一些定製處理,如claim的映射等。
/// <summary>
/// Configuration options for <see cref="FacebookHandler"/>.
/// </summary>
public class FacebookOptions : OAuthOptions
{
/// <summary>
/// Initializes a new <see cref="FacebookOptions"/>.
/// </summary>
public FacebookOptions()
{
CallbackPath = new PathString("/signin-facebook");
SendAppSecretProof = true;
AuthorizationEndpoint = FacebookDefaults.AuthorizationEndpoint;
TokenEndpoint = FacebookDefaults.TokenEndpoint;
UserInformationEndpoint = FacebookDefaults.UserInformationEndpoint;
Scope.Add("email");
Fields.Add("name");
Fields.Add("email");
Fields.Add("first_name");
Fields.Add("last_name");
ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "id");
ClaimActions.MapJsonSubKey("urn:facebook:age_range_min", "age_range", "min");
ClaimActions.MapJsonSubKey("urn:facebook:age_range_max", "age_range", "max");
ClaimActions.MapJsonKey(ClaimTypes.DateOfBirth, "birthday");
ClaimActions.MapJsonKey(ClaimTypes.Email, "email");
ClaimActions.MapJsonKey(ClaimTypes.Name, "name");
ClaimActions.MapJsonKey(ClaimTypes.GivenName, "first_name");
ClaimActions.MapJsonKey("urn:facebook:middle_name", "middle_name");
ClaimActions.MapJsonKey(ClaimTypes.Surname, "last_name");
ClaimActions.MapJsonKey(ClaimTypes.Gender, "gender");
ClaimActions.MapJsonKey("urn:facebook:link", "link");
ClaimActions.MapJsonSubKey("urn:facebook:location", "location", "name");
ClaimActions.MapJsonKey(ClaimTypes.Locality, "locale");
ClaimActions.MapJsonKey("urn:facebook:timezone", "timezone");
}
/// <summary>
/// Check that the options are valid. Should throw an exception if things are not ok.
/// </summary>
public override void Validate()
{
if (string.IsNullOrEmpty(AppId))
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, nameof(AppId)), nameof(AppId));
}
if (string.IsNullOrEmpty(AppSecret))
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, nameof(AppSecret)), nameof(AppSecret));
}
base.Validate();
}
// Facebook uses a non-standard term for this field.
/// <summary>
/// Gets or sets the Facebook-assigned appId.
/// </summary>
public string AppId
{
get { return ClientId; }
set { ClientId = value; }
}
// Facebook uses a non-standard term for this field.
/// <summary>
/// Gets or sets the Facebook-assigned app secret.
/// </summary>
public string AppSecret
{
get { return ClientSecret; }
set { ClientSecret = value; }
}
/// <summary>
/// Gets or sets if the appsecret_proof should be generated and sent with Facebook API calls.
/// This is enabled by default.
/// </summary>
public bool SendAppSecretProof { get; set; }
/// <summary>
/// The list of fields to retrieve from the UserInformationEndpoint.
/// https://developers.facebook.com/docs/graph-api/reference/user
/// </summary>
public ICollection<string> Fields { get; } = new HashSet<string>();
}
處理器類
重寫了OAuthHanlder的創建憑據方法,其他的都是使用的父類實現。
public class FacebookHandler : OAuthHandler<FacebookOptions>
{
public FacebookHandler(IOptionsMonitor<FacebookOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
: base(options, logger, encoder, clock)
{ }
protected override async Task<AuthenticationTicket> CreateTicketAsync(ClaimsIdentity identity, AuthenticationProperties properties, OAuthTokenResponse tokens)
{
var endpoint = QueryHelpers.AddQueryString(Options.UserInformationEndpoint, "access_token", tokens.AccessToken);
if (Options.SendAppSecretProof)
{
endpoint = QueryHelpers.AddQueryString(endpoint, "appsecret_proof", GenerateAppSecretProof(tokens.AccessToken));
}
if (Options.Fields.Count > 0)
{
endpoint = QueryHelpers.AddQueryString(endpoint, "fields", string.Join(",", Options.Fields));
}
var response = await Backchannel.GetAsync(endpoint, Context.RequestAborted);
if (!response.IsSuccessStatusCode)
{
throw new HttpRequestException($"An error occurred when retrieving Facebook user information ({response.StatusCode}). Please check if the authentication information is correct and the corresponding Facebook Graph API is enabled.");
}
using (var payload = JsonDocument.Parse(await response.Content.ReadAsStringAsync()))
{
var context = new OAuthCreatingTicketContext(new ClaimsPrincipal(identity), properties, Context, Scheme, Options, Backchannel, tokens, payload.RootElement);
context.RunClaimActions();
await Events.CreatingTicket(context);
return new AuthenticationTicket(context.Principal, context.Properties, Scheme.Name);
}
}
private string GenerateAppSecretProof(string accessToken)
{
using (var algorithm = new HMACSHA256(Encoding.ASCII.GetBytes(Options.AppSecret)))
{
var hash = algorithm.ComputeHash(Encoding.ASCII.GetBytes(accessToken));
var builder = new StringBuilder();
for (int i = 0; i < hash.Length; i++)
{
builder.Append(hash[i].ToString("x2", CultureInfo.InvariantCulture));
}
return builder.ToString();
}
}
protected override string FormatScope(IEnumerable<string> scopes)
{
// Facebook deviates from the OAuth spec here. They require comma separated instead of space separated.
// https://developers.facebook.com/docs/reference/dialogs/oauth
// http://tools.ietf.org/html/rfc6749#section-3.3
return string.Join(",", scopes);
}
protected override string FormatScope()
=> base.FormatScope();
}
Microsoft.AspNetCore.Authentication.Certificate
這個項目是3.1新加的,是做證書校驗的,具體的不細說了,不太懂,有興趣的看巨硬文檔
https://docs.microsoft.com/zh-cn/aspnet/core/security/authentication/certauth?view=aspnetcore-3.1
Microsoft.AspNetCore.Authentication.Negotiate
這個也是新增的項目,是做Windows校驗的,文檔如下
Microsoft.AspNetCore.Authentication.WsFederation
Windows的Azure Active Directory認證