AspNetCore 鉴权 <2.0>
概览
授权(Authentization):通过获取凭证中的基本信息,来判断用户能做什么,不能做什么。
授权也是通过中间件实现的,而且中间件注册时,授权只能放在认证的后面,因为认证其实是给用户颁发票据,其实就是context.user初始化,在授权将检查上一步颁发的票据中对应身份的声明,看是否由权限访问。如果权限出现问题会调用认证模型中的对应方法。所以认证授权是紧密相关的。
授权设计模式
概览
授权的核心是策略(AuthorizationPolicy),授权中间件找到注册的策略并提取Requirement,调用所有的IAuthorizationHandler的HandleAsync方法,获得Result,如果成功调用下一个中间件,失败则调用相应的认证方法。
AuthorizationMiddleware
- 通过AuthorizationPolicy的CombineAsync获取AuthorizationPolicyr策略
- 通过policyEvaluator调用AuthenticateAsync方法对策略中认证相关进行认证相关操作,并更新用户票据
- 通过policyEvaluator调用AuthorizeAsync方法调用IAuthorizationService服务的AuthorizeAsync方法,从而调用所有IAuthorizationHandler的HandleAsync进行鉴权,并获得鉴权结果
- 通过IAuthorizationMiddlewareResultHandler的HandleAsync方法对鉴权结果进行处理。
public class AuthorizationMiddleware
{
private const string SuppressUseHttpContextAsAuthorizationResource = "Microsoft.AspNetCore.Authorization.SuppressUseHttpContextAsAuthorizationResource";
private const string AuthorizationMiddlewareInvokedWithEndpointKey = "__AuthorizationMiddlewareWithEndpointInvoked";
private static readonly object AuthorizationMiddlewareWithEndpointInvokedValue = new object();
private readonly RequestDelegate _next;
private readonly IAuthorizationPolicyProvider _policyProvider;
public AuthorizationMiddleware(
RequestDelegate next,
IAuthorizationPolicyProvider policyProvider)
{
this._next = next ?? throw new ArgumentNullException(nameof (next));
this._policyProvider = policyProvider ?? throw new ArgumentNullException(nameof (policyProvider));
}
public async Task Invoke(HttpContext context)
{
Endpoint endpoint = context != null ? context.GetEndpoint() : throw new ArgumentNullException(nameof (context));
if (endpoint != null)
context.Items[(object) "__AuthorizationMiddlewareWithEndpointInvoked"] = AuthorizationMiddleware.AuthorizationMiddlewareWithEndpointInvokedValue;
Endpoint endpoint1 = endpoint;
AuthorizationPolicy policy = await AuthorizationPolicy.CombineAsync(this._policyProvider, (IEnumerable<IAuthorizeData>) ((endpoint1 != null ? (object) endpoint1.Metadata.GetOrderedMetadata<IAuthorizeData>() : (object) null) ?? (object) Array.Empty<IAuthorizeData>()));
IPolicyEvaluator policyEvaluator;
if (policy == null)
{
await this._next(context);
endpoint = (Endpoint) null;
policy = (AuthorizationPolicy) null;
policyEvaluator = (IPolicyEvaluator) null;
}
else
{
policyEvaluator = context.RequestServices.GetRequiredService<IPolicyEvaluator>();
AuthenticateResult authenticationResult = await policyEvaluator.AuthenticateAsync(policy, context);
if (endpoint?.Metadata.GetMetadata<IAllowAnonymous>() != null)
{
await this._next(context);
endpoint = (Endpoint) null;
policy = (AuthorizationPolicy) null;
policyEvaluator = (IPolicyEvaluator) null;
}
else
{
bool isEnabled;
object resource = !(AppContext.TryGetSwitch("Microsoft.AspNetCore.Authorization.SuppressUseHttpContextAsAuthorizationResource", out isEnabled) & isEnabled) ? (object) context : (object) endpoint;
PolicyAuthorizationResult authorizeResult = await policyEvaluator.AuthorizeAsync(policy, authenticationResult, context, resource);
await context.RequestServices.GetRequiredService<IAuthorizationMiddlewareResultHandler>().HandleAsync(this._next, context, policy, authorizeResult);
endpoint = (Endpoint) null;
policy = (AuthorizationPolicy) null;
policyEvaluator = (IPolicyEvaluator) null;
}
}
}
}
AuthorizationPolicy
该对象实际就包装了requirements,并通过AuthorizationPolicyBuilder对象创建自己
public class AuthorizationPolicy
{
public AuthorizationPolicy(
IEnumerable<IAuthorizationRequirement> requirements,
IEnumerable<string> authenticationSchemes)
{
if (requirements == null)
throw new ArgumentNullException(nameof (requirements));
if (authenticationSchemes == null)
throw new ArgumentNullException(nameof (authenticationSchemes));
this.Requirements = requirements.Any<IAuthorizationRequirement>() ? (IReadOnlyList<IAuthorizationRequirement>) new List<IAuthorizationRequirement>(requirements).AsReadOnly() : throw new InvalidOperationException(Resources.Exception_AuthorizationPolicyEmpty);
this.AuthenticationSchemes = (IReadOnlyList<string>) new List<string>(authenticationSchemes).AsReadOnly();
}
public IReadOnlyList<IAuthorizationRequirement> Requirements { get; }
public IReadOnlyList<string> AuthenticationSchemes { get; }
public static AuthorizationPolicy Combine(
params AuthorizationPolicy[] policies)
{
return policies != null ? AuthorizationPolicy.Combine((IEnumerable<AuthorizationPolicy>) policies) : throw new ArgumentNullException(nameof (policies));
}
public static AuthorizationPolicy Combine(
IEnumerable<AuthorizationPolicy> policies)
{
if (policies == null)
throw new ArgumentNullException(nameof (policies));
AuthorizationPolicyBuilder authorizationPolicyBuilder = new AuthorizationPolicyBuilder(Array.Empty<string>());
foreach (AuthorizationPolicy policy in policies)
authorizationPolicyBuilder.Combine(policy);
return authorizationPolicyBuilder.Build();
}
public static async Task<AuthorizationPolicy?> CombineAsync(
IAuthorizationPolicyProvider policyProvider,
IEnumerable<IAuthorizeData> authorizeData)
{
if (policyProvider == null)
throw new ArgumentNullException(nameof (policyProvider));
if (authorizeData == null)
throw new ArgumentNullException(nameof (authorizeData));
bool flag1 = false;
if (authorizeData is IList<IAuthorizeData> authorizeDataList)
flag1 = authorizeDataList.Count == 0;
AuthorizationPolicyBuilder policyBuilder = (AuthorizationPolicyBuilder) null;
if (!flag1)
{
foreach (IAuthorizeData authorizeDatum in authorizeData)
{
if (policyBuilder == null)
policyBuilder = new AuthorizationPolicyBuilder(Array.Empty<string>());
bool flag2 = true;
if (!string.IsNullOrWhiteSpace(authorizeDatum.Policy))
{
policyBuilder.Combine(await policyProvider.GetPolicyAsync(authorizeDatum.Policy) ?? throw new InvalidOperationException(Resources.FormatException_AuthorizationPolicyNotFound((object) authorizeDatum.Policy)));
flag2 = false;
}
string[] source = authorizeDatum.Roles?.Split(',');
if (source != null && source.Length != 0)
{
policyBuilder.RequireRole(((IEnumerable<string>) source).Where<string>((Func<string, bool>) (r => !string.IsNullOrWhiteSpace(r))).Select<string, string>((Func<string, string>) (r => r.Trim())));
flag2 = false;
}
string[] strArray = authorizeDatum.AuthenticationSchemes?.Split(',');
if (strArray != null && strArray.Length != 0)
{
foreach (string str in strArray)
{
if (!string.IsNullOrWhiteSpace(str))
policyBuilder.AuthenticationSchemes.Add(str.Trim());
}
}
if (flag2)
{
AuthorizationPolicyBuilder authorizationPolicyBuilder = policyBuilder;
authorizationPolicyBuilder.Combine(await policyProvider.GetDefaultPolicyAsync());
authorizationPolicyBuilder = (AuthorizationPolicyBuilder) null;
}
}
}
if (policyBuilder == null)
{
AuthorizationPolicy fallbackPolicyAsync = await policyProvider.GetFallbackPolicyAsync();
if (fallbackPolicyAsync != null)
return fallbackPolicyAsync;
}
return policyBuilder?.Build();
}
}
AuthorizationPolicyBuilder
public class AuthorizationPolicyBuilder
{
public AuthorizationPolicyBuilder(params string[] authenticationSchemes) => this.AddAuthenticationSchemes(authenticationSchemes);
public AuthorizationPolicyBuilder(AuthorizationPolicy policy) => this.Combine(policy);
public IList<IAuthorizationRequirement> Requirements { get; set; } = (IList<IAuthorizationRequirement>) new List<IAuthorizationRequirement>();
public IList<string> AuthenticationSchemes { get; set; } = (IList<string>) new List<string>();
public AuthorizationPolicyBuilder AddAuthenticationSchemes(
params string[] schemes)
{
foreach (string scheme in schemes)
this.AuthenticationSchemes.Add(scheme);
return this;
}
public AuthorizationPolicyBuilder AddRequirements(
params IAuthorizationRequirement[] requirements)
{
foreach (IAuthorizationRequirement requirement in requirements)
this.Requirements.Add(requirement);
return this;
}
public AuthorizationPolicyBuilder Combine(AuthorizationPolicy policy)
{
if (policy == null)
throw new ArgumentNullException(nameof (policy));
this.AddAuthenticationSchemes(policy.AuthenticationSchemes.ToArray<string>());
this.AddRequirements(policy.Requirements.ToArray<IAuthorizationRequirement>());
return this;
}
public AuthorizationPolicyBuilder RequireClaim(
string claimType,
params string[] allowedValues)
{
return claimType != null ? this.RequireClaim(claimType, (IEnumerable<string>) allowedValues) : throw new ArgumentNullException(nameof (claimType));
}
public AuthorizationPolicyBuilder RequireClaim(
string claimType,
IEnumerable<string> allowedValues)
{
if (claimType == null)
throw new ArgumentNullException(nameof (claimType));
this.Requirements.Add((IAuthorizationRequirement) new ClaimsAuthorizationRequirement(claimType, allowedValues));
return this;
}
public AuthorizationPolicyBuilder RequireClaim(string claimType)
{
if (claimType == null)
throw new ArgumentNullException(nameof (claimType));
this.Requirements.Add((IAuthorizationRequirement) new ClaimsAuthorizationRequirement(claimType, (IEnumerable<string>) null));
return this;
}
public AuthorizationPolicyBuilder RequireRole(params string[] roles) => roles != null ? this.RequireRole((IEnumerable<string>) roles) : throw new ArgumentNullException(nameof (roles));
public AuthorizationPolicyBuilder RequireRole(
IEnumerable<string> roles)
{
if (roles == null)
throw new ArgumentNullException(nameof (roles));
this.Requirements.Add((IAuthorizationRequirement) new RolesAuthorizationRequirement(roles));
return this;
}
public AuthorizationPolicyBuilder RequireUserName(string userName)
{
if (userName == null)
throw new ArgumentNullException(nameof (userName));
this.Requirements.Add((IAuthorizationRequirement) new NameAuthorizationRequirement(userName));
return this;
}
public AuthorizationPolicyBuilder RequireAuthenticatedUser()
{
this.Requirements.Add((IAuthorizationRequirement) new DenyAnonymousAuthorizationRequirement());
return this;
}
public AuthorizationPolicyBuilder RequireAssertion(
Func<AuthorizationHandlerContext, bool> handler)
{
if (handler == null)
throw new ArgumentNullException(nameof (handler));
this.Requirements.Add((IAuthorizationRequirement) new AssertionRequirement(handler));
return this;
}
public AuthorizationPolicyBuilder RequireAssertion(
Func<AuthorizationHandlerContext, Task<bool>> handler)
{
if (handler == null)
throw new ArgumentNullException(nameof (handler));
this.Requirements.Add((IAuthorizationRequirement) new AssertionRequirement(handler));
return this;
}
public AuthorizationPolicy Build() => new AuthorizationPolicy((IEnumerable<IAuthorizationRequirement>) this.Requirements, this.AuthenticationSchemes.Distinct<string>());
}
IPolicyEvaluator
通过这两个接口分别处理策略的认证和授权
public interface IPolicyEvaluator
{
Task<AuthenticateResult> AuthenticateAsync(
AuthorizationPolicy policy,
HttpContext context);
Task<PolicyAuthorizationResult> AuthorizeAsync(
AuthorizationPolicy policy,
AuthenticateResult authenticationResult,
HttpContext context,
object? resource);
}
PolicyEvaluator
public class PolicyEvaluator : IPolicyEvaluator
{
private readonly IAuthorizationService _authorization;
public PolicyEvaluator(IAuthorizationService authorization) => this._authorization = authorization;
public virtual async Task<AuthenticateResult> AuthenticateAsync(
AuthorizationPolicy policy,
HttpContext context)
{
if (policy.AuthenticationSchemes == null || policy.AuthenticationSchemes.Count <= 0)
return context.User?.Identity?.IsAuthenticated.GetValueOrDefault() ? AuthenticateResult.Success(new AuthenticationTicket(context.User, "context.User")) : AuthenticateResult.NoResult();
ClaimsPrincipal newPrincipal = (ClaimsPrincipal) null;
foreach (string authenticationScheme in (IEnumerable<string>) policy.AuthenticationSchemes)
{
AuthenticateResult authenticateResult = await context.AuthenticateAsync(authenticationScheme);
if (authenticateResult != null && authenticateResult.Succeeded)
newPrincipal = SecurityHelper.MergeUserPrincipal(newPrincipal, authenticateResult.Principal);
}
if (newPrincipal != null)
{
context.User = newPrincipal;
return AuthenticateResult.Success(new AuthenticationTicket(newPrincipal, string.Join(";", (IEnumerable<string>) policy.AuthenticationSchemes)));
}
context.User = new ClaimsPrincipal((IIdentity) new ClaimsIdentity());
return AuthenticateResult.NoResult();
}
public virtual async Task<PolicyAuthorizationResult> AuthorizeAsync(
AuthorizationPolicy policy,
AuthenticateResult authenticationResult,
HttpContext context,
object? resource)
{
if (policy == null)
throw new ArgumentNullException(nameof (policy));
AuthorizationResult authorizationResult = await this._authorization.AuthorizeAsync(context.User, resource, policy);
return !authorizationResult.Succeeded ? (authenticationResult.Succeeded ? PolicyAuthorizationResult.Forbid(authorizationResult.Failure) : PolicyAuthorizationResult.Challenge()) : PolicyAuthorizationResult.Success();
}
}
IAuthorizationService
public interface IAuthorizationService
{
Task<AuthorizationResult> AuthorizeAsync(
ClaimsPrincipal user,
object? resource,
IEnumerable<IAuthorizationRequirement> requirements);
Task<AuthorizationResult> AuthorizeAsync(
ClaimsPrincipal user,
object? resource,
string policyName);
}
DefaultAuthorizationService
public class DefaultAuthorizationService : IAuthorizationService
{
private readonly AuthorizationOptions _options;
private readonly IAuthorizationHandlerContextFactory _contextFactory;
private readonly IAuthorizationHandlerProvider _handlers;
private readonly IAuthorizationEvaluator _evaluator;
private readonly IAuthorizationPolicyProvider _policyProvider;
private readonly ILogger _logger;
public DefaultAuthorizationService(
IAuthorizationPolicyProvider policyProvider,
IAuthorizationHandlerProvider handlers,
ILogger<DefaultAuthorizationService> logger,
IAuthorizationHandlerContextFactory contextFactory,
IAuthorizationEvaluator evaluator,
IOptions<AuthorizationOptions> options)
{
if (options == null)
throw new ArgumentNullException(nameof (options));
if (policyProvider == null)
throw new ArgumentNullException(nameof (policyProvider));
if (handlers == null)
throw new ArgumentNullException(nameof (handlers));
if (logger == null)
throw new ArgumentNullException(nameof (logger));
if (contextFactory == null)
throw new ArgumentNullException(nameof (contextFactory));
if (evaluator == null)
throw new ArgumentNullException(nameof (evaluator));
this._options = options.Value;
this._handlers = handlers;
this._policyProvider = policyProvider;
this._logger = (ILogger) logger;
this._evaluator = evaluator;
this._contextFactory = contextFactory;
}
public virtual async Task<AuthorizationResult> AuthorizeAsync(
ClaimsPrincipal user,
object? resource,
IEnumerable<IAuthorizationRequirement> requirements)
{
if (requirements == null)
throw new ArgumentNullException(nameof (requirements));
AuthorizationHandlerContext authContext = this._contextFactory.CreateContext(requirements, user, resource);
foreach (IAuthorizationHandler authorizationHandler in await this._handlers.GetHandlersAsync(authContext))
{
await authorizationHandler.HandleAsync(authContext);
if (!this._options.InvokeHandlersAfterFailure)
{
if (authContext.HasFailed)
break;
}
}
AuthorizationResult authorizationResult1 = this._evaluator.Evaluate(authContext);
if (authorizationResult1.Succeeded)
this._logger.UserAuthorizationSucceeded();
else
this._logger.UserAuthorizationFailed(authorizationResult1.Failure);
AuthorizationResult authorizationResult2 = authorizationResult1;
authContext = (AuthorizationHandlerContext) null;
return authorizationResult2;
}
public virtual async Task<AuthorizationResult> AuthorizeAsync(
ClaimsPrincipal user,
object? resource,
string policyName)
{
DefaultAuthorizationService service = this;
if (policyName == null)
throw new ArgumentNullException(nameof (policyName));
AuthorizationPolicy policyAsync = await service._policyProvider.GetPolicyAsync(policyName);
if (policyAsync == null)
throw new InvalidOperationException("No policy found: " + policyName + ".");
return await service.AuthorizeAsync(user, resource, policyAsync);
}
}
IAuthorizationHandlerContextFactory
在调用IAuthorizationHandler之前会构建上下文环境,通过AuthorizationHandlerContextFactory创建一个AuthorizationHandlerContext对象。工厂方法
public interface IAuthorizationHandlerContextFactory
{
AuthorizationHandlerContext CreateContext(
IEnumerable<IAuthorizationRequirement> requirements,
ClaimsPrincipal user,
object? resource);
}
DefaultAuthorizationHandlerContextFactory
public class DefaultAuthorizationHandlerContextFactory : IAuthorizationHandlerContextFactory
{
public virtual AuthorizationHandlerContext CreateContext(
IEnumerable<IAuthorizationRequirement> requirements,
ClaimsPrincipal user,
object? resource)
{
return new AuthorizationHandlerContext(requirements, user, resource);
}
}
AuthorizationHandlerContext
该上下文保存着用户,requirements其是从policy中取的,
public class AuthorizationHandlerContext
{
private HashSet<IAuthorizationRequirement> _pendingRequirements;
private bool _failCalled;
private bool _succeedCalled;
public AuthorizationHandlerContext(
IEnumerable<IAuthorizationRequirement> requirements,
ClaimsPrincipal user,
object? resource)
{
this.Requirements = requirements != null ? requirements : throw new ArgumentNullException(nameof (requirements));
this.User = user;
this.Resource = resource;
this._pendingRequirements = new HashSet<IAuthorizationRequirement>(requirements);
}
public virtual IEnumerable<IAuthorizationRequirement> Requirements { get; }
public virtual ClaimsPrincipal User { get; }
public virtual object? Resource { get; }
public virtual IEnumerable<IAuthorizationRequirement> PendingRequirements => (IEnumerable<IAuthorizationRequirement>) this._pendingRequirements;
public virtual bool HasFailed => this._failCalled;
public virtual bool HasSucceeded => !this._failCalled && this._succeedCalled && !this.PendingRequirements.Any<IAuthorizationRequirement>();
public virtual void Fail() => this._failCalled = true;
public virtual void Succeed(IAuthorizationRequirement requirement)
{
this._succeedCalled = true;
this._pendingRequirements.Remove(requirement);
}
}
IAuthorizationMiddlewareResultHandler
通过其处理结果并调用认证相关接口
public interface IAuthorizationMiddlewareResultHandler
{
Task HandleAsync(
RequestDelegate next,
HttpContext context,
AuthorizationPolicy policy,
PolicyAuthorizationResult authorizeResult);
}
AuthorizationMiddlewareResultHandler
public class AuthorizationMiddlewareResultHandler : IAuthorizationMiddlewareResultHandler
{
public async Task HandleAsync(
RequestDelegate next,
HttpContext context,
AuthorizationPolicy policy,
PolicyAuthorizationResult authorizeResult)
{
if (authorizeResult.Challenged)
{
if (policy.AuthenticationSchemes.Count > 0)
{
foreach (string authenticationScheme in (IEnumerable<string>) policy.AuthenticationSchemes)
await context.ChallengeAsync(authenticationScheme);
}
else
await context.ChallengeAsync();
}
else if (authorizeResult.Forbidden)
{
if (policy.AuthenticationSchemes.Count > 0)
{
foreach (string authenticationScheme in (IEnumerable<string>) policy.AuthenticationSchemes)
await context.ForbidAsync(authenticationScheme);
}
else
await context.ForbidAsync();
}
else
await next(context);
}
}
依赖注入
AuthorizationServiceCollectionExtensions
public static class AuthorizationServiceCollectionExtensions
{
public static IServiceCollection AddAuthorizationCore(
this IServiceCollection services)
{
if (services == null)
throw new ArgumentNullException(nameof (services));
services.AddOptions();
services.TryAdd(ServiceDescriptor.Transient<IAuthorizationService, DefaultAuthorizationService>());
services.TryAdd(ServiceDescriptor.Transient<IAuthorizationPolicyProvider, DefaultAuthorizationPolicyProvider>());
services.TryAdd(ServiceDescriptor.Transient<IAuthorizationHandlerProvider, DefaultAuthorizationHandlerProvider>());
services.TryAdd(ServiceDescriptor.Transient<IAuthorizationEvaluator, DefaultAuthorizationEvaluator>());
services.TryAdd(ServiceDescriptor.Transient<IAuthorizationHandlerContextFactory, DefaultAuthorizationHandlerContextFactory>());
services.TryAddEnumerable(ServiceDescriptor.Transient<IAuthorizationHandler, PassThroughAuthorizationHandler>());
return services;
}
public static IServiceCollection AddAuthorizationCore(
this IServiceCollection services,
Action<AuthorizationOptions> configure)
{
if (services == null)
throw new ArgumentNullException(nameof (services));
if (configure == null)
throw new ArgumentNullException(nameof (configure));
services.Configure<AuthorizationOptions>(configure);
return services.AddAuthorizationCore();
}
}
PolicyServiceCollectionExtensions
public static class PolicyServiceCollectionExtensions
{
public static IServiceCollection AddAuthorizationPolicyEvaluator(
this IServiceCollection services)
{
if (services == null)
throw new ArgumentNullException(nameof (services));
services.TryAddSingleton<AuthorizationPolicyMarkerService>();
services.TryAddTransient<IPolicyEvaluator, PolicyEvaluator>();
services.TryAddTransient<IAuthorizationMiddlewareResultHandler, AuthorizationMiddlewareResultHandler>();
return services;
}
public static IServiceCollection AddAuthorization(
this IServiceCollection services)
{
if (services == null)
throw new ArgumentNullException(nameof (services));
services.AddAuthorizationCore();
services.AddAuthorizationPolicyEvaluator();
return services;
}
public static IServiceCollection AddAuthorization(
this IServiceCollection services,
Action<AuthorizationOptions> configure)
{
if (services == null)
throw new ArgumentNullException(nameof (services));
services.AddAuthorizationCore(configure);
services.AddAuthorizationPolicyEvaluator();
return services;
}
}
您的资助是我最大的动力!
金额随意,欢迎来赏!
作者:阿杜聊编程
出处:https://www.cnblogs.com/lovexinyi/
版权:本文版权归作者和博客园共有
转载:欢迎转载,但未经作者同意,必须保留此段声明;必须在文章中给出原文链接;否则必究法律责任
出处:https://www.cnblogs.com/lovexinyi/
版权:本文版权归作者和博客园共有
转载:欢迎转载,但未经作者同意,必须保留此段声明;必须在文章中给出原文链接;否则必究法律责任