ABP框架源码学习之授权逻辑

asp.net core的默认的几种授权方法参考“雨夜朦胧”的系列博客,这里要强调的是asp.net core mvc中的授权和asp.net mvc中的授权不一样,建议先看前面“雨夜朦胧”的博客。

Abp中Controller里面用到的权限验证类为:AbpMvcAuthorizeAttribute,ApplicationService里面用到的权限验证类为:AbpAuthorizeAttribute(见下图)。

AbpMvcAuthorizeAttributeAbpAuthorizeAttribute这两个类全部继承自IAbpAuthorizeAttribute(重要!!!),下面是这两个类的源码。

 1 namespace Abp.Authorization
 2 {
 3     /// <summary>
 4     /// This attribute is used on a method of an Application Service (A class that implements <see cref="IApplicationService"/>)
 5     /// to make that method usable only by authorized users.
 6     /// </summary>
 7     [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
 8     public class AbpAuthorizeAttribute : Attribute, IAbpAuthorizeAttribute
 9     {
10         /// <summary>
11         /// A list of permissions to authorize.
12         /// </summary>
13         public string[] Permissions { get; }
14 
15         /// <summary>
16         /// If this property is set to true, all of the <see cref="Permissions"/> must be granted.
17         /// If it's false, at least one of the <see cref="Permissions"/> must be granted.
18         /// Default: false.
19         /// </summary>
20         public bool RequireAllPermissions { get; set; }
21 
22         /// <summary>
23         /// Creates a new instance of <see cref="AbpAuthorizeAttribute"/> class.
24         /// </summary>
25         /// <param name="permissions">A list of permissions to authorize</param>
26         public AbpAuthorizeAttribute(params string[] permissions)
27         {
28             Permissions = permissions;
29         }
30     }
31 }
View Code
 1 namespace Abp.AspNetCore.Mvc.Authorization
 2 {
 3     /// <summary>
 4     /// This attribute is used on an action of an MVC <see cref="Controller"/>
 5     /// to make that action usable only by authorized users. 
 6     /// </summary>
 7     [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
 8     public class AbpMvcAuthorizeAttribute : AuthorizeAttribute, IAbpAuthorizeAttribute
 9     {
10         /// <inheritdoc/>
11         public string[] Permissions { get; set; }
12 
13         /// <inheritdoc/>
14         public bool RequireAllPermissions { get; set; }
15 
16         /// <summary>
17         /// Creates a new instance of <see cref="AbpMvcAuthorizeAttribute"/> class.
18         /// </summary>
19         /// <param name="permissions">A list of permissions to authorize</param>
20         public AbpMvcAuthorizeAttribute(params string[] permissions)
21         {
22             Permissions = permissions;
23         }
24     }
25 }
View Code

重点来啦!!!

 

 1 namespace Abp.AspNetCore.Mvc.Authorization
 2 {
 3     public class AbpAuthorizationFilter : IAsyncAuthorizationFilter, ITransientDependency
 4     {
 5         public ILogger Logger { get; set; }
 6 
 7         private readonly IAuthorizationHelper _authorizationHelper;
 8         private readonly IErrorInfoBuilder _errorInfoBuilder;
 9         private readonly IEventBus _eventBus;
10 
11         public AbpAuthorizationFilter(
12             IAuthorizationHelper authorizationHelper,
13             IErrorInfoBuilder errorInfoBuilder,
14             IEventBus eventBus)
15         {
16             _authorizationHelper = authorizationHelper;
17             _errorInfoBuilder = errorInfoBuilder;
18             _eventBus = eventBus;
19             Logger = NullLogger.Instance;
20         }
21 
22         public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
23         {
24             // 判断context中是否有继承IAllowAnoymousFilter,有则跳出方法即验证成功
25             if (context.Filters.Any(item => item is IAllowAnonymousFilter))
26             {
27                 return;
28             }
29        //判断是否是Controller,具体方法见下面第一张截图
30             if (!context.ActionDescriptor.IsControllerAction())
31             {
32                 return;
33             }
34 
35             //TODO: Avoid using try/catch, use conditional checking
36             try
37             {
38                 await _authorizationHelper.AuthorizeAsync(
39                     context.ActionDescriptor.GetMethodInfo(),
40                     context.ActionDescriptor.GetMethodInfo().DeclaringType
41                 );
42             }
43             catch (AbpAuthorizationException ex)
44             {
45                 Logger.Warn(ex.ToString(), ex);
46 
47                 _eventBus.Trigger(this, new AbpHandledExceptionData(ex));
48 
49                 if (ActionResultHelper.IsObjectResult(context.ActionDescriptor.GetMethodInfo().ReturnType))
50                 {
51                     context.Result = new ObjectResult(new AjaxResponse(_errorInfoBuilder.BuildForException(ex), true))
52                     {
53                         StatusCode = context.HttpContext.User.Identity.IsAuthenticated
54                             ? (int) System.Net.HttpStatusCode.Forbidden
55                             : (int) System.Net.HttpStatusCode.Unauthorized
56                     };
57                 }
58                 else
59                 {
60                     context.Result = new ChallengeResult();
61                 }
62             }
63             catch (Exception ex)
64             {
65                 Logger.Error(ex.ToString(), ex);
66 
67                 _eventBus.Trigger(this, new AbpHandledExceptionData(ex));
68 
69                 if (ActionResultHelper.IsObjectResult(context.ActionDescriptor.GetMethodInfo().ReturnType))
70                 {
71                     context.Result = new ObjectResult(new AjaxResponse(_errorInfoBuilder.BuildForException(ex)))
72                     {
73                         StatusCode = (int) System.Net.HttpStatusCode.InternalServerError
74                     };
75                 }
76                 else
77                 {
78                     //TODO: How to return Error page?
79                     context.Result = new StatusCodeResult((int)System.Net.HttpStatusCode.InternalServerError);
80                 }
81             }
82         }
83     }
84 }

 

 
AbpAuthorizationFilter继承自IAsyncAuthorizationFilter和ITransientDependency,其中继承自ITransientDependency 是为了注入这个类,继承IAsyncAuthorizationFilter这个接口下面会写到。
其中AbpAuthorizationFilter类的OnAuthorizationAsync这个方法是验证授权的最重要的一个地方,其中_authorizationHelper.AuthorizeAsync是通过反射得到是否有继承自IAbpAuthorizeAttribute接口的特性,即AbpMvcAuthorizeAttributeAbpAuthorizeAttribute,然后得到这个特性标识的权限,然后PermissionChecker检验用户是否具有这个权限。
 
现在我们知道AbpAuthorizationFilter的主要任务就是通过判断controller或者service的标识的权限对比用户是否具有这个权限来达到授权验证。那AbpAuthorizationFilter怎么触发的呢,也就是什么时候调用的呢,,从下图我们可以看出当我们调用AddAbp这个方法时,也就是在Startup类里面调用AddAbp时,就会在MvcOptions里面FilterCollection里面添加AbpAuthorizationFilter,当我们访问一个Controller或者ApplicationService时就会触发这个filter,判断权限。

拓展:当我们有某个业务需要用到AOP时,但又不想使用一些第三方框架,我们就可以借鉴上面的方法,定义一个特性,然后定义一个Filter,在Filter里面判断Controller等是否使用这些特性,并且特性的属性是否符合我们的需求,最后在Startup里面AddMvc时将这个Filter添加到FilterCollection里面。例如下图,自动验证AntiforgeryToken

 


 


 

 

 

posted @ 2018-02-27 10:06  王Uncle  阅读(1839)  评论(0编辑  收藏  举报