身份管理模块(Identity模块)为通用查询接口的按组织架构查询和按户关系查询提供查询依据。
身份管理模块的领域层依赖Volo.Abp.Identity.Domain
Abp为我们实现了一套身份管理模块,此模块包含用户管理、角色管理、组织管理、权限管理等功能。详细请参考身份管理模块。
我们将基于Volo.Abp.Identity模块按需求扩展。将为其扩展组织管理功能的接口,以及人员关系(Relation)功能。
用户关系管理
Relation是人员之间的关系,比如:签约、关注,或者朋友关系等。人员之间的关系是单项的,也就是说可以A是B的好友,但B不一定是A的好友。
关系类型由Type来定义
正向关系:User -> RelatedUser,由查询GetRelatedToUsersAsync实现;
反向关系:RelatedUser -> User,由查询GetRelatedFromUsersAsync实现。
添加Relation实体:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class Relation : FullAuditedAggregateRoot<long> { public Guid? TenantId { get; set; }
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] public override long Id { get; protected set; }
public Guid UserId { get; set; }
[ForeignKey("UserId")] public IdentityUser User { get; set; }
public Guid RelatedUserId { get; set; }
[ForeignKey("RelatedUserId")] public IdentityUser RelatedUser { get; set; }
public string Type { get; set; }
}
|
在模块配置中添加
1 2 3 4 5 6 7 8 9 10 11 12
| public class IdentityEntityFrameworkCoreModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) { context.Services.AddAbpDbContext<IdentityDbContext>(options => { options.AddRepository<IdentityUserOrganizationUnit, EfCoreRepository<IdentityDbContext, IdentityUserOrganizationUnit>>(); options.AddRepository<Relation.Relation, EfCoreRepository<IdentityDbContext, Relation.Relation>>(); }); } }
|
创建RelationManager,实现人员关系的正向和反向查询
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public async Task<List<Relation>> GetRelatedToUsersAsync(Guid userId, string type) { var query = (await Repository.GetQueryableAsync()) .WhereIf(userId != null, c => userId == c.UserId) .WhereIf(!string.IsNullOrEmpty(type), c => c.Type == type); var items = query.ToList(); return items;
}
public async Task<List<Relation>> GetRelatedFromUsersAsync(Guid userId, string type) { var query = (await Repository.GetQueryableAsync()) .Where(c => userId == c.RelatedUserId) .WhereIf(!string.IsNullOrEmpty(type), c => c.Type == type); var items = query.ToList(); return items; }
|
扩展组织管理功能
组织(OrganizationUnit)是身份管理模块的核心概念,组织是树形结构,组织之间存在父子关系。
我们对功能模块的接口进行扩展:
增加OrganizationUnit的增删查改接口;
增加OrganizationUnit的移动接口;
增加人员与组织架构管理接口,如添加/删除人员到组织架构,查询组织架构下的人员,查询未分配组织的人员等;
增加查询根组织(GetRootOrganizationUnit)接口。
完整的应用层接口如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public interface IOrganizationUnitAppService : IBasicCurdAppService<OrganizationUnitDto, Guid, CreateOrganizationUnitInput, UpdateOrganizationUnitInput>, IApplicationService { Task AddToOrganizationUnitAsync(UserToOrganizationUnitInput input); Task<List<OrganizationUnitDto>> GetCurrentOrganizationUnitsAsync(); Task<PagedResultDto<IdentityUserDto>> GetOrganizationUnitUsersByPageAsync(GetOrganizationUnitUsersInput input); Task<List<IdentityUserDto>> GetOrganizationUnitUsersAsync(GetOrganizationUnitUsersInput input); Task<OrganizationUnitDto> GetRootOrganizationUnitAsync(Guid id); Task<List<OrganizationUnitDto>> GetRootOrganizationUnitsAsync(IEnumerable<Guid> ids); Task<OrganizationUnitDto> GetRootOrganizationUnitByDisplayNameAsync(GetRootOrganizationUnitByDisplayName input); Task<List<OrganizationUnitDto>> GetRootOrganizationUnitsByParentAsync(GetRootOrganizationUnitsByParentInput input); Task<bool> IsInOrganizationUnitAsync(UserToOrganizationUnitInput input); Task MoveOrganizationUnitAsync(MoveOrganizationUnitInput input); Task RemoveUserFromOrganizationUnitAsync(UserToOrganizationUnitInput input); Task<List<IdentityUserDto>> GetUsersWithoutOrganizationAsync(GetUserWithoutOrganizationInput input); Task<PagedResultDto<IdentityUserDto>> GetUsersWithoutOrganizationByPageAsync(GetUserWithoutOrganizationInput input); }
|
创建可查询仓储
通用查询接口过滤条件需要对IQueryable进行拼接,由于Volo.Abp.Identity.IIdentityUserRepository继承自IBasicRepository,我们需要重新编写一个IdentityUser的可查询仓储:QueryableIdentityUserRepository
其实现接口IQueryableIdentityUserRepository的定义如下:
1 2 3 4 5 6 7 8
| public interface IQueryableIdentityUserRepository : IIdentityUserRepository { Task<IQueryable<OrganizationUnit>> GetOrganizationUnitsQueryableAsync(Guid id, bool includeDetails = false); Task<IQueryable<IdentityUser>> GetOrganizationUnitUsersAsync( Guid id, string keyword, string[] type, bool includeDetails = false); Task<IQueryable<IdentityUser>> GetUsersWithoutOrganizationAsync(string keyword, string[] type); }
|
实现控制器
为OrganizationUnitAppService 以及 RelationAppService 创建MVC控制器
完整的 OrganizationUnitController 代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
| namespace Matoapp.Identity.OrganizationUnit { [Area(IdentityRemoteServiceConsts.ModuleName)] [RemoteService(Name = IdentityRemoteServiceConsts.RemoteServiceName)] [Route("api/identity/organizationUnit")] public class OrganizationUnitController : IdentityController, IOrganizationUnitAppService { private readonly IOrganizationUnitAppService _organizationUnitAppService;
public OrganizationUnitController(IOrganizationUnitAppService organizationUnitAppService) { _organizationUnitAppService = organizationUnitAppService; }
[HttpPost] [Route("AddToOrganizationUnit")] public async Task AddToOrganizationUnitAsync(UserToOrganizationUnitInput input) { await _organizationUnitAppService.AddToOrganizationUnitAsync(input); }
[HttpPost] [Route("Create")] public async Task<OrganizationUnitDto> CreateAsync(CreateOrganizationUnitInput input) { return await _organizationUnitAppService.CreateAsync(input); }
[HttpDelete] [Route("Delete")] public async Task DeleteAsync(Guid id) { await _organizationUnitAppService.DeleteAsync(id); }
[HttpGet] [Route("Get")] public async Task<OrganizationUnitDto> GetAsync(Guid id) { return await _organizationUnitAppService.GetAsync(id);
}
[HttpGet] [Route("GetCurrentOrganizationUnits")]
public async Task<List<OrganizationUnitDto>> GetCurrentOrganizationUnitsAsync() { return await _organizationUnitAppService.GetCurrentOrganizationUnitsAsync(); }
[HttpGet] [Route("GetOrganizationUnitUsers")] public async Task<List<IdentityUserDto>> GetOrganizationUnitUsersAsync(GetOrganizationUnitUsersInput input) { return await _organizationUnitAppService.GetOrganizationUnitUsersAsync(input); }
[HttpGet] [Route("GetOrganizationUnitUsersByPage")] public async Task<PagedResultDto<IdentityUserDto>> GetOrganizationUnitUsersByPageAsync(GetOrganizationUnitUsersInput input) { return await _organizationUnitAppService.GetOrganizationUnitUsersByPageAsync(input); }
[HttpGet] [Route("GetRootOrganizationUnit")] public async Task<OrganizationUnitDto> GetRootOrganizationUnitAsync(Guid id) { return await _organizationUnitAppService.GetRootOrganizationUnitAsync(id); }
[HttpGet] [Route("GetRootOrganizationUnits")] public async Task<List<OrganizationUnitDto>> GetRootOrganizationUnitsAsync(IEnumerable<Guid> ids) { return await _organizationUnitAppService.GetRootOrganizationUnitsAsync(ids); }
[HttpGet] [Route("GetRootOrganizationUnitByDisplayName")] public async Task<OrganizationUnitDto> GetRootOrganizationUnitByDisplayNameAsync(GetRootOrganizationUnitByDisplayName input) { return await _organizationUnitAppService.GetRootOrganizationUnitByDisplayNameAsync(input); }
[HttpGet] [Route("GetRootOrganizationUnitsByParent")] public async Task<List<OrganizationUnitDto>> GetRootOrganizationUnitsByParentAsync(GetRootOrganizationUnitsByParentInput input) { return await _organizationUnitAppService.GetRootOrganizationUnitsByParentAsync(input); }
[HttpGet] [Route("GetUsersWithoutOrganization")] public async Task<List<IdentityUserDto>> GetUsersWithoutOrganizationAsync(GetUserWithoutOrganizationInput input) { return await _organizationUnitAppService.GetUsersWithoutOrganizationAsync(input); }
[HttpGet] [Route("GetUsersWithoutOrganizationByPage")] public async Task<PagedResultDto<IdentityUserDto>> GetUsersWithoutOrganizationByPageAsync(GetUserWithoutOrganizationInput input) { return await _organizationUnitAppService.GetUsersWithoutOrganizationByPageAsync(input); }
[HttpGet] [Route("IsInOrganizationUnit")] public async Task<bool> IsInOrganizationUnitAsync(UserToOrganizationUnitInput input) { return await _organizationUnitAppService.IsInOrganizationUnitAsync(input); }
[HttpPost] [Route("MoveOrganizationUnit")] public async Task MoveOrganizationUnitAsync(MoveOrganizationUnitInput input) { await _organizationUnitAppService.MoveOrganizationUnitAsync(input); }
[HttpPost] [Route("RemoveUserFromOrganizationUnit")] public async Task RemoveUserFromOrganizationUnitAsync(UserToOrganizationUnitInput input) { await _organizationUnitAppService.RemoveUserFromOrganizationUnitAsync(input); }
[HttpPut] [Route("Update")] public async Task<OrganizationUnitDto> UpdateAsync(UpdateOrganizationUnitInput input) { return await _organizationUnitAppService.UpdateAsync(input); }
}
|
完整的 RelationController 代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
| [Area(IdentityRemoteServiceConsts.ModuleName)] [RemoteService(Name = IdentityRemoteServiceConsts.RemoteServiceName)] [Route("api/identity/relation")] public class RelationController : IdentityController, IRelationAppService { private readonly IRelationAppService _relationAppService;
public RelationController(IRelationAppService relationAppService) { _relationAppService = relationAppService; }
[HttpDelete] [Route("ClearAllRelatedFromUsers")]
public async Task ClearAllRelatedFromUsersAsync(GetRelatedUsersInput input) { await _relationAppService.ClearAllRelatedFromUsersAsync(input); }
[HttpDelete] [Route("ClearAllRelatedToUsers")]
public async Task ClearAllRelatedToUsersAsync(GetRelatedUsersInput input) { await _relationAppService.ClearAllRelatedToUsersAsync(input); }
[HttpPost] [Route("Create")]
public async Task<RelationDto> CreateAsync(ModifyRelationInput input) { return await _relationAppService.CreateAsync(input); }
[HttpDelete] [Route("Delete")]
public async Task DeleteAsync(EntityDto<long> input) { await _relationAppService.DeleteAsync(input); }
[HttpDelete] [Route("DeleteByUserId")]
public async Task DeleteByUserIdAsync(ModifyRelationInput input) { await _relationAppService.DeleteByUserIdAsync(input); }
[HttpGet] [Route("GetRelatedFromUsers")]
public async Task<List<IdentityUserDto>> GetRelatedFromUsersAsync(GetRelatedUsersInput input) { return await _relationAppService.GetRelatedFromUsersAsync(input); }
[HttpGet] [Route("GetRelatedToUsers")]
public async Task<List<IdentityUserDto>> GetRelatedToUsersAsync(GetRelatedUsersInput input) { return await _relationAppService.GetRelatedToUsersAsync(input); }
[HttpGet] [Route("GetRelatedToUserIds")] public async Task<List<Guid>> GetRelatedToUserIdsAsync(GetRelatedUsersInput input) { return await _relationAppService.GetRelatedToUserIdsAsync(input); }
[HttpGet] [Route("GetRelatedFromUserIds")] public async Task<List<Guid>> GetRelatedFromUserIdsAsync(GetRelatedUsersInput input) { return await _relationAppService.GetRelatedFromUserIdsAsync(input); }
}
|
测试接口
上一章节我们已经将三个模组的依赖添加到MatoappHttpApiModule中,直接启动HttpApi.Host就可以访问接口了。
1 2 3 4 5 6 7
| [DependsOn( ... typeof(CommonHttpApiModule), typeof(HealthHttpApiModule), typeof(IdentityHttpApiModule) )] public class MatoappHttpApiModule : AbpModule
|
Relation相关接口:
OrganizationUnit相关接口:
下一章节将介绍如何利用Identity模块为用户的查询提供组织架构和用户关系的条件过滤。