## 4.4 ABP应用层 - 权限认证
几乎所有的企业级应用程序都会有不同级别的权限验证。权限验证是用于检查用户是否允许某些指定操作。Abp有基础设施让你来实现权限验证。
>**注意:关于IPermissionChecker接口**
>
>Abp权限系统使用IPermissionChecker去检查授权。同时你可以根据需要实现你自己的方式,在module-zero项目中已经完整实现了。如果IPermissionChecker没有被实现,NullPermissionChecker会被使用于授权所有权限给每个人。
### 4.4.1 定义权限
在使用验证权限前,我们需要为每一个操作定义唯一的权限。Abp的设计是基于模块化,所以不同的模块可以有不同的权限。为了定义权限,一个模块应该创建AuthorizationProvider的派生类。MyAuthorizationProvider继承自AuthorizationProvider,换句话说就是AuthorizationProvider派生出MyAuthorizationProvider。例子如下:
```csharp
public class MyAuthorizationProvider : AuthorizationProvider
{
public override void SetPermissions(IPermissionDefinitionContext context)
{
var administration = context.CreatePermission("Administration");
var userManagement = administration.CreateChildPermission("Administration.UserManagement");
userManagement.CreateChildPermission("Administration.UserManagement.CreateUser");
var roleManagement = administration.CreateChildPermission("Administration.RoleManagement");
}
}
```
IPermissionDefinitionContext 有方法去获取和创建权限。
一个权限有以下属性:
* Name:系统范围内的唯一名字。把它定义为一个字符串常量是个不错的注意。我们倾向于将“.”分割不同的层级,但并不要求这么做。你可以设置你任何喜欢的名字。唯一的规则就是这个名字必须是唯一的。
* Display Name:使用一个本地化的字符串去显示权限到UI。
* Description:和Display Name类似。
* MultiTenancySides:对租户应用程序,一个权限可以基于租户或者主机(原文:host)。这是个枚举标识,因此权限可以应用于不同方面(原文:Both Sides)。
* dependedFeature:能够被用来描述某个被依赖的功能。那么,只有在该依赖的功能被满足的情况下该权限才被授予
一个权限可以有父权限和子权限。当然,这不会影响权限检查,它只是在UI层对权限归类有好处。创建authorizationprovider之后,我们应该在模块的PreIntialize方法对它进行注册。如下:
```csharp
Configuration.Authorization.Providers.Add<MyAuthorizationProvider>()
```
authorizationprovider会自动注册到依赖注入系统中。因此,authorization provider可以注入任何依赖(像是Repository)从而使用其他资源去创建权限定义。
### 4.4.2 检查权限 ###
**(1)使用AbpAuthorize特性(Using AbpAuthorize attribute)**
AbpAuthorize(AbpMvcAuthorize 对应 MVC Controllers and AbpApiAuthorize 对应 Web API Controllers)特性是最简单和常用的方法去检查权限。请考虑如下application service方法:
```csharp
[AbpAuthorize("Administration.UserManagement.CreateUser")]
public void CreateUser(CreateUserInput input)
{
//A user can not execute this method if he is not granted for "Administration.UserManagement.CreateUser" permission.
}
```
没有获得“Administration.UserManagement.CreateUser”权限的用户不能够调用CreateUser。
AbpAuthorize 特性也检查当前用户是否登录 (使用 IAbpSession.UserId)。因此,如果我们将某个方法声明为AbpAuthorize 特性,它至少会检查用户是否登录。代码如下:
[AbpAuthorize]
```csharp
public void SomeMethod(SomeMethodInput input)
{
//A user can not execute this method if he did not login.
}
```
**(2)AbpAuthorize属性说明(AbpAuthorize attribute notes)**
Abp使用动态方法拦截进行权限验证。因此,使用AbpAuthorize特性的方法会有些限制。如下:
* 不能应用于私有(private)方法
* 不能应用于静态(static)方法
* 不能应用于非注入(non-injected)类(我们必须用依赖注入)。
此外,
* AbpAuthorize特性可以应用于任何的Public方法,如果此方法被接口调用(比如在Application Services中通过接口调用)
* 方法是虚(virtual)方法,如果此方法直接被类引用进行调用(像是ASP.NET MVC 或 Web API 的控制器)。
* 方式是虚(virtual)方法,如果此方法是protected。
注意:有四种 AbpAuthorize 特性:
* 在应用程序服务中(application layer),我们使用 **Abp.Authorization.AbpAuthorize**;
* 在MVC控制器(web layer)中,我们使用 **Abp.Web.Mvc.Authorization.AbpMvcAuthorize**;
* 在ASP.NET Web API,我们使用 **Abp.WebApi.Authorization.AbpApiAuthorize**;
* 在ASP.NET Core,我们使用 **Abp.AspNetCore.Mvc.Authorization.AbpMvcAuthorize**。
这些类继承自不同的地方。
这三个类继承自不同的地方。在Application 层,它完全是由Abp自己实现没有扩展子任何类。但是,在MVC和Web API中它继承自它们框架中各自的 Authorize 特性。
##### Suppress Authorization
你可以对应用服务中某个方法或者类使用 **AbpAllowAnonymous** 特性来禁用认证许可。对于在MVC,Web API以及ASP.NET Core控制器禁用认证许可,你应该使用它们各自框架中的 **AllowAnonymous** 特性。
**(3)使用IPermissionChecker**
AbpAuthorize 适用于大部分的情况,但是某些情况下,我们还是需要自己在方法体里进行权限验证。我们可以注入和使用IPermissionChecker对象。如下边的代码所示:
```csharp
public void CreateUser(CreateOrUpdateUserInput input)
{
if (!PermissionChecker.IsGranted("Administration.UserManagement.CreateUser"))
{
throw new AbpAuthorizationException("You are not authorized to create user!");
}
//如果该用户没有 "Administration.UserManagement.CreateUser" 的权限,那么它就不能运行到这个地方。
}
```
当然,你可以写入任何逻辑,由于IsGranted方法只是简单返回true或false(它还有异步版本哦)。如你简单的检查一个权限并抛出一个异常如上边代码那样,你可以用Authorize方法:
```csharp
public void CreateUser(CreateOrUpdateUserInput input)
{
PermissionChecker.Authorize("Administration.UserManagement.CreateUser");
//如果该用户没有 "Administration.UserManagement.CreateUser" 的权限,那么它就不能运行到这个地方。
}
```
由于权限验证通常实现于Application层,ApplicationService基础类注入和定义了PermissionChecker属性。因此,权限检查器允许你在Application Service类使用,而不需要显式注入。
#### 在Razor视图中
在视图基类中定义了 **IsGranted** 方法来检查当前用户时候具有某个权限。因此我们可以有条件的来渲染视图,例如:
```csharp
@if (IsGranted("Administration.UserManagement.CreateUser"))
{
<button id="CreateNewUserButton" class="btn btn-primary"><i class="fa fa-plus"></i> @L("CreateNewUser")</button>
}
```
#### 客户端
在客户端,我们可以使用定义在 **abp.auth** 命名空间中的API。在大多数情况下,我们需要检查当前用户时候具有指定的权限。例如:
```javascript
abp.auth.isGranted('Administration.UserManagement.CreateUser');
```
你也可以使用 **abp.auth.grantedPermissions** 来获取所有的权限或者使用 **abp.auth.allPermissions** 来获取应用中所有有效的权限名称。
- 文章&教程
- Abp
- 1.1ABP总体介绍-入门介绍
- 1.2ABP总体介绍-多层架构体系
- 1.3ABP总体介绍-模块系统
- 1.4ABP总体介绍-启动配置
- 1.5ABP总体介绍-多租户
- 1.6ABP总体介绍-集成OWIN
- 2.1ABP公共结构-依赖注入
- 2.2ABP公共结构-会话管理
- 2.3ABP公共结构-缓存管理
- 2.4ABP公共结构-日志管理
- 2.5ABP公共结构-设置管理
- 2.6ABP公共结构-时区设置
- 3.1ABP领域层-实体
- 3.2ABP领域层-值对象
- 3.3ABP领域层-仓储
- 3.4ABP领域层-领域服务
- 3.5ABP领域层-工作单元
- 3.6ABP领域层-领域事件
- 3.7ABP领域层-数据过滤器
- 4.1ABP应用层-应用服务
- 4.2ABP应用层-数据传输对象
- 4.3ABP应用层-数据传输对象验证
- 4.4ABP应用层-权限认证
- 4.5ABP应用层-功能管理
- 4.6ABP应用层-审计日志
- 5.1ABP分布式服务-ASP.NET WebApi
- 5.2ABP分布式服务-动态WebApi层
- 5.3ABP分布式服务-集成OData
- 5.4ABP分布式服务-集成SwaggerUI
- 6.1ABP表现层-Mvc控制器
- 6.2ABP表现层-Mvc视图
- 6.3ABP表现层-本地化
- 6.4ABP表现层-导航栏
- 6.5ABP表现层-异常处理
- 6.6.2-AJAX
- 6.6.3-Notification
- 6.6.4-Message
- 6.6.5-UIBlockBusy
- 6.6.6-EventBus
- 6.6.7-Logging
- 6.6.8-OtherUtilities
- 6.6ABP表现层-JavascriptAPI
- 6.7ABP表现层-嵌入资源文件
- 6.8ASP.NET-Core
- 6.9CSRF和XSRF保护
- 7.1ABP后台服务-后台作业和工人
- 7.2ABP后台服务-集成Hangfire
- 8.1ABP实时服务-通知系统
- 8.2ABP实时服务-集成SignalR
- 9.1ABP基础设施层-集成Entity Framework
- 9.2ABP基础设施层-集成NHibernate
- 9.3ABP基础设施层-集成Entity Framework Core
- abp合并版160929
- md文档排版规范
- AbpZero
- 1.1ABPZero-概述
- 1.2ABPZero-安装
- 1.3ABPZero-启动模板
- 1.4ABPZero-启动模板Core
- 2.1ABPZero-多租户管理
- 2.2ABPZero-版本管理
- 2.4ABPZero-组织单位管理