本系列將分析ASP.NET Core運行原理 "【ASP.NET Core】運行原理(1):創建WebHost" "【ASP.NET Core】運行原理(2):啟動WebHost" "【ASP.NET Core】運行原理(3):認證" 【ASP.NET Core】運行原理(4):授權 在認證階段通過 ...
本系列將分析ASP.NET Core運行原理
- 【ASP.NET Core】運行原理(1):創建WebHost
- 【ASP.NET Core】運行原理(2):啟動WebHost
- 【ASP.NET Core】運行原理(3):認證
- 【ASP.NET Core】運行原理(4):授權
在認證階段通過用戶令牌獲取到用戶的Claims,而授權就是對這些Claims的驗證。
目錄
- 授權核心
- AuthorizationOptions
- AuthorizationPolicy
- AuthorizationPolicyBuilder
- 執行授權
- AuthorizeFilter
- IPolicyEvaluator
- IAuthorizationService
- 總結
授權核心
services.AddAuthorization(opt => opt.AddPolicy("isAdmin", builder => builder.RequireUserName("admin")));
通過上面的代碼,可以添加一個isAdmin的授權。
對於第一個參數opt:
public class AuthorizationOptions
{
private IDictionary<string, AuthorizationPolicy> PolicyMap { get; } = new Dictionary<string, AuthorizationPolicy>();
public void AddPolicy(string name, AuthorizationPolicy policy)
{
PolicyMap[name] = policy;
}
public void AddPolicy(string name, Action<AuthorizationPolicyBuilder> configurePolicy)
{
var policyBuilder = new AuthorizationPolicyBuilder();
configurePolicy(policyBuilder);
AddPolicy(name,policyBuilder.Build());
}
public AuthorizationPolicy GetPolicy(string name)
{
return PolicyMap.ContainsKey(name) ? PolicyMap[name] : null;
}
}
實際上,AuthorizationOptions
相當於AuthorizationPolicy的集合
而AuthorizationPolicy
則是一個具體的授權策略對象
public class AuthorizationPolicy
{
public IReadOnlyList<IAuthorizationRequirement> Requirements { get; }
public IReadOnlyList<string> AuthenticationSchemes { get; }
}
而AuthorizationPolicyBuilder
通過Build方法可以構建一個AuthorizationPolicy,其內部有很多常用的添加IAuthorizationRequirement
的方法:
public AuthorizationPolicy Build()
{
return new AuthorizationPolicy(this.Requirements, this.AuthenticationSchemes);
}
public AuthorizationPolicyBuilder RequireUserName(string userName)
{
this.Requirements.Add(new NameAuthorizationRequirement(userName));
}
... Require() ...
IAuthorizationRequirement
是授權策略AuthorizationPolicy
的一個授權條件,策略下的所有授權條件滿足,則授權成功。
public interface IAuthorizationRequirement
{
}
public class NameAuthorizationRequirement : IAuthorizationRequirement
{
public string RequiredName { get; }
}
IAuthorizationHandler
是授權條件IAuthorizationRequirement
的具體處理器,授權條件下的任意1個處理器授權成功,則授權成功。(預設情況下:AuthorizationOptions的InvokeHandlersAfterFailure = true)
public interface IAuthorizationHandler
{
Task HandleAsync(AuthorizationHandlerContext context);
}
public abstract class AuthorizationHandler<TRequirement> : IAuthorizationHandler where TRequirement : IAuthorizationRequirement
{
public virtual async Task HandleAsync(AuthorizationHandlerContext context)
{
foreach (TRequirement requirement in context.Requirements)
await HandleRequirementAsync(context, requirement);
}
protected abstract Task HandleRequirementAsync(AuthorizationHandlerContext context, TRequirement requirement);
}
public class NameAuthorizationRequirement : AuthorizationHandler<NameAuthorizationRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, NameAuthorizationRequirement requirement)
{
if (context.User?.Identities.Any(identity => identity.Name == requirement.RequiredName))
context.Succeed((IAuthorizationRequirement) requirement);
return Task.CompletedTask;
}
}
授權的最終實現代碼在IAuthorizationHandler
執行授權
解釋了授權策略的原理,再談談授權策略的觸發。通常我們在MVC中使用授權功能,而觸發授權也是在註冊MVC代碼中,一併註冊了。
public static IMvcBuilder AddMvc(this IServiceCollection services)
{
IMvcCoreBuilder builder = services.AddMvcCore();
builder.AddAuthorization();
}
internal static void AddAuthorizationServices(IServiceCollection services)
{
services.AddAuthenticationCore();
services.AddAuthorization();
services.AddAuthorizationPolicyEvaluator();
services.TryAddEnumerable(ServiceDescriptor.Transient<IApplicationModelProvider, AuthorizationApplicationModelProvider>());
}
在MVC中,ApplicationModel用來描述MVC中的模型,而IApplicationModelProvider則是初始化MVC的模型:
public class ApplicationModel
{
public IList<ControllerModel> Controllers { get; }
public IList<IFilterMetadata> Filters { get; }
}
public interface IApplicationModelProvider
{
int Order { get; }
void OnProvidersExecuting(ApplicationModelProviderContext context);
void OnProvidersExecuted(ApplicationModelProviderContext context);
}
其中AuthorizationApplicationModelProvider會初始化ApplicationModel的授權部分,註冊到Filters屬性上(AuthorizeFilter 和 AllowAnonymousFilter)。
public interface IAsyncAuthorizationFilter : IFilterMetadata
{
Task OnAuthorizationAsync(AuthorizationFilterContext context);
}
public class AuthorizeFilter : IAsyncAuthorizationFilter
{
public virtual async Task OnAuthorizationAsync(AuthorizationFilterContext context)
{
var policyEvaluator = GetRequiredService<IPolicyEvaluator>();
var authenticationResult = await policyEvaluator.AuthenticateAsync(effectivePolicy, context.HttpContext);
var authorizationResult = await policyEvaluator.AuthorizeAsync(effectivePolicy, authenticationResult, context.HttpContext, context);
if (authorizationResult.Challenged)
{
context.Result = (IActionResult) new ChallengeResult((IList<string>) effectivePolicy.AuthenticationSchemes.ToArray<string>());
}
else if (authorizationResult.Forbidden)
{
context.Result = (IActionResult) new ForbidResult((IList<string>) effectivePolicy.AuthenticationSchemes.ToArray<string>());
}
}
}
AuthorizeFilter的OnAuthorizationAsync方法會在Action執行前觸發,內部調用IPolicyEvaluator執行
public interface IPolicyEvaluator
{
Task<AuthenticateResult> AuthenticateAsync(AuthorizationPolicy policy, HttpContext context);
Task<PolicyAuthorizationResult> AuthorizeAsync(AuthorizationPolicy policy, AuthenticateResult authenticationResult, HttpContext context, object resource);
}
public class PolicyEvaluator : IPolicyEvaluator
{
private readonly IAuthorizationService _authorization;
public virtual async Task<AuthenticateResult> AuthenticateAsync(AuthorizationPolicy policy, HttpContext context)
{
}
public virtual async Task<PolicyAuthorizationResult> AuthorizeAsync(AuthorizationPolicy policy, AuthenticateResult authenticationResult, HttpContext context, object resource)
{
var result = await _authorization.AuthorizeAsync(context.User, resource, policy);
if (result.Succeeded) return PolicyAuthorizationResult.Success();
return (authenticationResult.Succeeded) ? PolicyAuthorizationResult.Forbid() : PolicyAuthorizationResult.Challenge();
}
}
在AuthenticateAsync方法中,將合併policy的所有scheme認證結果。
在AuthorizeAsync方法中,將調用IAuthorizationService
來實現授權。
public interface IAuthorizationService
{
Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user, object resource, IEnumerable<IAuthorizationRequirement> requirements);
Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user, object resource, string policyName);
}
public class DefaultAuthorizationService : IAuthorizationService
{
public async Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user, object resource, string policyName)
{
var policy = await _policyProvider.GetPolicyAsync(policyName);
return await this.AuthorizeAsync(user, resource, policy);
}
public async Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user, object resource, IEnumerable<IAuthorizationRequirement> requirements)
{
var authContext = _contextFactory.CreateContext(requirements, user, resource);
var handlers = await _handlers.GetHandlersAsync(authContext);
foreach (var handler in handlers)
{
await handler.HandleAsync(authContext);
if (!_options.InvokeHandlersAfterFailure && authContext.HasFailed)
break;
}
return _evaluator.Evaluate(authContext);
}
}
在IAuthorizationService類中,將調用policy的所有Requirement的Handle處理
總結
授權核心:AuthorizationOptions
、AuthorizationPolicy
、AuthorizationPolicyBuilder
AuthorizationOptions 用於保存 AuthorizationPolicy
AuthorizationPolicyBuilder 用於創建 AuthorizationPolicy
AuthorizationPolicy 包含 IAuthorizationRequirement 和 AuthenticationSchemes
IAuthorizationRequirement 包含授權邏輯 IAuthorizationHandler
執行授權:AuthorizeFilter
、IPolicyEvaluator
、IAuthorizationService
AuthorizeFilter的OnAuthorizationAsync方法會在Action執行前觸發,內部調用IPolicyEvaluator執行
IPolicyEvaluator 先根據 Schemes 獲取Claims,然後調用 IAuthorizationService 的授權方法
IAuthorizationService 調用 Requirement 對應的Handle授權邏輯
個人覺得源碼的一個待優化的地方:在DefaultAuthorizationHandlerProvider
的GetHandlersAsync
方法按需返回IAuthorizationHandler
更合適。
本文鏈接:http://www.cnblogs.com/neverc/p/8204339.html