Abp VNext微服务-从身份认证及授权开始(二)
接上篇:Abp VNext微服务-从身份认证及授权开始(一)
上篇新增了一个日志查看模块,这次新增一个用于管理IdentityServer的Client、Api resources、Identity resources、Claims等等
效果:
权限管理
一,切换到modules目录,新增IdentityServer管理模块
\Liujb-AbpVnext-MicServices\modules> abp new Kingsun.Liujb.IDManagement -t module -csf
按需引用:
二,添加声明(Claims)管理功能
1,添加声明管理服务相关接口及Dto
public class ClaimDto: EntityDto<Guid> { public string Name { get; set; } public bool Required { get; set; } public bool IsStatic { get; set; } public string Description { get; set; } public string ConcurrencyStamp { get; set; } } public class CreateClaimDto:CreateOrUpdateClaimBaseDto { [Required] [MaxLength(64)] public string Name { get; set; } } public class CreateOrUpdateClaimBaseDto: ExtensibleObject { public bool Required { get; set; } public string Description { get; set; } } public class GetClaimsInput : PagedAndSortedResultRequestDto { public string Filter { get; set; } } public interface IClaimsService:ICrudAppService<ClaimDto,Guid,GetClaimsInput,CreateClaimDto,UpdateClaimDto>,IApplicationService { } public class UpdateClaimDto:CreateOrUpdateClaimBaseDto { [Required] public string ConcurrencyStamp { get; set; } }
2,实现声明管理服务
[Authorize(Permissions.IDManagementPermissions.Claims.Defalut)] public class ClaimsService : IDManagementAppService, IClaimsService { private readonly IdenityClaimTypeManager _idenityClaimTypeManager; private readonly IIdentityClaimTypeRepository _identityClaimTypeRepository; public ClaimsService(IdenityClaimTypeManager idenityClaimTypeManager, IIdentityClaimTypeRepository identityClaimTypeRepository) { this._idenityClaimTypeManager = idenityClaimTypeManager; this._identityClaimTypeRepository = identityClaimTypeRepository; } [Authorize(Permissions.IDManagementPermissions.Claims.Create)] public async Task<ClaimDto> CreateAsync(CreateClaimDto input) { var claim = new IdentityClaimType( id: GuidGenerator.Create(), name: input.Name, isStatic:false, description:input.Description ); var reslut=await _idenityClaimTypeManager.CreateAsync(claim); return ObjectMapper.Map<IdentityClaimType, ClaimDto>(reslut); } [Authorize(Permissions.IDManagementPermissions.Claims.Delete)] public async Task DeleteAsync(Guid id) { var claim = await _identityClaimTypeRepository.GetAsync(id); if (claim == null) { throw new BusinessException(code: ExceptionCodes.ClaimNotFound).WithData("0",id); } if (claim.IsStatic) { throw new BusinessException(code: ExceptionCodes.CanNotDeleteAStaticClaim); } await _identityClaimTypeRepository.DeleteAsync(claim); } public async Task<ClaimDto> GetAsync(Guid id) { var reslut =await _identityClaimTypeRepository.GetAsync(id); if(reslut==null) throw new BusinessException(code: ExceptionCodes.ClaimNotFound).WithData("0",id); return ObjectMapper.Map<IdentityClaimType, ClaimDto>(reslut); } public async Task<PagedResultDto<ClaimDto>> GetListAsync(GetClaimsInput input) { long count =await _identityClaimTypeRepository.GetCountAsync(); var list =await _identityClaimTypeRepository.GetPagedListAsync( skipCount: input.SkipCount, maxResultCount: input.MaxResultCount, sorting: input.Sorting ); var retList= ObjectMapper.Map<List<IdentityClaimType>, List<ClaimDto>>(list); return new PagedResultDto<ClaimDto>() { Items = retList, TotalCount = count }; } [Authorize(Permissions.IDManagementPermissions.Claims.Update)] public async Task<ClaimDto> UpdateAsync(Guid id, UpdateClaimDto input) { var exsit =await _identityClaimTypeRepository.GetAsync(id); if(exsit==null) throw new BusinessException(code: ExceptionCodes.ClaimNotFound).WithData("0", id); exsit.ConcurrencyStamp = input.ConcurrencyStamp; exsit.Description = input.Description; exsit.Required = input.Required; var reslut= await _idenityClaimTypeManager.UpdateAsync(exsit); return ObjectMapper.Map<IdentityClaimType, ClaimDto>(reslut); } }
3,使用webapi暴露服务
[RemoteService] [Route("api/IDManagement/Claims")] public class ClaimsController : IDManagementController, IClaimsService { public IClaimsService ClaimService { get; set; } public ClaimsController(IClaimsService _claimServices) { this.ClaimService = _claimServices; } [HttpPost] public Task<ClaimDto> CreateAsync(CreateClaimDto input) { return ClaimService.CreateAsync(input); } [HttpDelete] [Route("{id}")] public Task DeleteAsync(Guid id) { return ClaimService.DeleteAsync(id); } [HttpGet] [Route("{id}")] public Task<ClaimDto> GetAsync(Guid id) { return ClaimService.GetAsync(id); } [HttpGet] public Task<PagedResultDto<ClaimDto>> GetListAsync(GetClaimsInput input) { return ClaimService.GetListAsync(input); } [HttpPut] [Route("{id}")] public Task<ClaimDto> UpdateAsync(Guid id, UpdateClaimDto input) { return ClaimService.UpdateAsync(id,input); } }
查看swagger,验证相关接口
4,添加相关界面
4.1 Claims/Index
管理主页:Index.cshtml
@page @using Microsoft.Extensions.Localization @using Kingsun.Liujb.IDManagement.Localization @using Kingsun.Liujb.IDManagement.Permissions @using Microsoft.AspNetCore.Authorization @inject IStringLocalizer<IDManagementResource> L @inject IAuthorizationService Authorization @model Kingsun.Liujb.IDManagement.Web.Pages.Claims.IndexModel @section scripts{ <abp-script src="/Pages/Claims/Index.js" /> } <abp-card id="ClaimsWrapper"> <abp-card-header> <abp-row> <abp-column size-md="_6"> <abp-card-title>@L["Cliams"]</abp-card-title> </abp-column> <abp-column size-md="_6" class="text-right"> @if (await Authorization.IsGrantedAsync(IDManagementPermissions.Clients.Create)) { <abp-button button-type="Primary" name="CreateClaim" text="@L["NewClaim"].Value" icon="plus" /> } </abp-column> </abp-row> </abp-card-header> <abp-card-body> <abp-table striped-rows="true" id="CliamsTable"></abp-table> </abp-card-body> </abp-card>
index.js
(function ($) { var l = abp.localization.getResource('IDManagement'); var _claimsServices = kingsun.liujb.iDManagement.claims.claims; var _permissionsModal = new abp.ModalManager( abp.appPath + 'AbpPermissionManagement/PermissionManagementModal' ); var _editModal = new abp.ModalManager( abp.appPath + 'Claims/EditModal' ); var _createModal = new abp.ModalManager( abp.appPath + 'Claims/CreateModal' ); var _dataTable = null; abp.ui.extensions.entityActions.get('iDManagement.claims').addContributor( function (actionList) { return actionList.addManyTail( [ { text: l('Edit'), visible: abp.auth.isGranted( 'IDManagement.Claims.Update' ), action: function (data) { _editModal.open({ id: data.record.id, }); }, }, { text: l('Delete'), visible: function (data) { return ( abp.auth.isGranted( 'IDManagement.Claims.Delete' ) ); //TODO: Check permission }, confirmMessage: function (data) { return l( 'ConfirmDeletedClaim', data.record.name ); }, action: function (data) { _claimsServices .delete(data.record.id) .then(function () { _dataTable.ajax.reload(); }); }, } ] ); } ); abp.ui.extensions.tableColumns.get('iDManagement.claims').addContributor( function (columnList) { columnList.addManyTail( [ { title: l("Actions"), rowAction: { items: abp.ui.extensions.entityActions.get('iDManagement.claims').actions.toArray() } }, { title: l('Name'), data: 'name', }, { title: l('Description'), data: 'description', }, { title: l('Staic'), data: 'IsStatic', render: function (data, type, row) { var sdata = "<input type='checkbox' readonly checked disabled/>" if (!row.isStatic) { sdata = "<input type='checkbox' readonly disabled/>" } return sdata; } } ] ); }, 0 //adds as the first contributor ); $(function () { var _$wrapper = $('#ClaimsWrapper'); var _$table = _$wrapper.find('table'); _dataTable = _$table.DataTable( abp.libs.datatables.normalizeConfiguration({ order: [[1, 'asc']], searching: false, processing: true, serverSide: true, scrollX: true, paging: true, ajax: abp.libs.datatables.createAjax( _claimsServices.getList ), columnDefs: abp.ui.extensions.tableColumns.get('iDManagement.claims').columns.toArray() }) ); _createModal.onResult(function () { _dataTable.ajax.reload(); }); _editModal.onResult(function () { _dataTable.ajax.reload(); }); _$wrapper.find('button[name=CreateClaim]').click(function (e) { console.log("create"); e.preventDefault(); _createModal.open(); }); }); })(jQuery);
4.2 创建页
CreateModal.cshtml
@page @model Kingsun.Liujb.IDManagement.Web.Pages.Claims.CreateModalModel @using Microsoft.AspNetCore.Mvc.Localization @using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal @using Microsoft.Extensions.Localization @using Kingsun.Liujb.IDManagement; @using Kingsun.Liujb.IDManagement.Localization; @using Kingsun.Liujb.IDManagement.Permissions; @inject IHtmlLocalizer<IDManagementResource> L @inject IStringLocalizerFactory StringLocalizerFactory @{ Layout = null; } <form asp-page="/Claims/CreateModal" method="post"> <abp-modal> <abp-modal-header title="@L["NewClaim"].Value"></abp-modal-header> <abp-modal-body> <abp-input asp-for="Claim.Name" /> <abp-input asp-for="Claim.Description" /> </abp-modal-body> <abp-modal-footer buttons="@(AbpModalButtons.Cancel|AbpModalButtons.Save)"></abp-modal-footer> </abp-modal> </form> public class CreateModalModel : IDManagementPageModel { private readonly Kingsun.Liujb.IDManagement.Claims.IClaimsService _claimsService; public CreateModalModel(IClaimsService claimsService) { this._claimsService = claimsService; } [BindProperty] public ClaimInfoModle Claim { get; set; } public class ClaimInfoModle: ExtensibleObject { [Required] [MaxLength(64)] [Display(Name ="DisplayName:ClaimName")] public string Name { get; set; } [MaxLength(1000)] [Display(Name = "DisplayName:Description")] public string Description { get; set; } } public virtual Task<IActionResult> OnGetAsync() { Claim = new ClaimInfoModle(); return Task.FromResult<IActionResult>(Page()); } public virtual async Task<IActionResult> OnPostAsync() { ValidateModel(); var input = ObjectMapper.Map<ClaimInfoModle, CreateClaimDto>(this.Claim); await _claimsService.CreateAsync(input); return NoContent(); } }
4.3 编辑页
EditModal.cshtml
@page @model Kingsun.Liujb.IDManagement.Web.Pages.Claims.EditModalModel @using Microsoft.AspNetCore.Mvc.Localization @using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal @using Microsoft.Extensions.Localization @using Kingsun.Liujb.IDManagement; @using Kingsun.Liujb.IDManagement.Localization; @using Kingsun.Liujb.IDManagement.Permissions; @inject IHtmlLocalizer<IDManagementResource> L @inject IStringLocalizerFactory StringLocalizerFactory @{ Layout = null; } <form asp-page="/Claims/EditModal" method="post"> <abp-modal> <abp-modal-header title="@L["EditClaim"].Value"></abp-modal-header> <abp-modal-body> <input type="hidden" asp-for="ClaimInfo.ConcurrencyStamp" /> <input type="hidden" asp-for="ClaimInfo.Id" /> <abp-input asp-for="ClaimInfo.Name" readonly="true"/> <abp-input asp-for="ClaimInfo.Description" /> </abp-modal-body> <abp-modal-footer buttons="@(AbpModalButtons.Cancel|AbpModalButtons.Save)"></abp-modal-footer> </abp-modal> </form> using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Threading.Tasks; using Kingsun.Liujb.IDManagement.Claims; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using Volo.Abp.Application.Dtos; namespace Kingsun.Liujb.IDManagement.Web.Pages.Claims { public class EditModalModel : IDManagementPageModel { [BindProperty] public UpdateClaimInfo ClaimInfo { get; set; } [BindProperties] public class UpdateClaimInfo:EntityDto<Guid> { [Required] public string ConcurrencyStamp { get; set; } public bool Required { get; set; }=false; public string Description { get; set; } public string Name { get; set; } } private readonly IClaimsService _claimService; public EditModalModel(IClaimsService claimService) { this._claimService = claimService; } public async Task<IActionResult> OnGetAsync(Guid id) { var claim=await _claimService.GetAsync(id); this.ClaimInfo = ObjectMapper.Map<ClaimDto, UpdateClaimInfo>(claim); return Page(); } public async Task<IActionResult> OnPostAsync() { ValidateModel(); var input = ObjectMapper.Map<UpdateClaimInfo, UpdateClaimDto>(this.ClaimInfo); await _claimService.UpdateAsync(this.ClaimInfo.Id, input); return NoContent(); } } }
4.3 效果
三,添加IdentityServer相关管理功能
Volo.Abp.IdentityServer相关模块是基于.netcore app而不是.net standard,所以我们新建一个新的类库,但是目标框架为.net core。可以新建一个console程序,修改输出类型即可。
1,和前面声明管理模块一样,先添加管理服务相关接口及Dto,基本上差不太多
2,实现服务
这里贴一个client的管理服务实现类
[Authorize(Permissions.IDManagementPermissions.Clients.Defalut)] public class ClientsService : IDManagementIdentityServerAppservice, IClientsService { private readonly IClientRepository _clientRepository; private readonly IIdentityResourceRepository _identityResourceRepository; private readonly IApiResourceRepository _apiResourceRepository; public ClientsService(IClientRepository clientRepository , IIdentityResourceRepository _identityResourceRepository, IApiResourceRepository _apiResourceRepository) { this._apiResourceRepository = _apiResourceRepository; this._identityResourceRepository = _identityResourceRepository; this._clientRepository = clientRepository; } [Authorize(Permissions.IDManagementPermissions.Clients.Create)] public async Task<ClientDto> CreateAsync(CreateClientDto input) { var exsit = await _clientRepository.FindByCliendIdAsync(input.ClientName); if (exsit != null) throw new BusinessException(ExceptionCodes.ClientAreadyFound).WithData("0",input.ClientName); var insert = new Client(GuidGenerator.Create(), input.ClientName); ObjectMapper.Map<CreateClientDto, Client>(input,insert); insert.ClientName = input.ClientName; insert = await _clientRepository.InsertAsync(insert, true); await UpdateClientExaAsync(client: insert, input.AllowedScopes, input.GrantTypes, input.RedirectUris, input.PostLogoutRedirectUris, input.Secret); return ObjectMapper.Map<Client, ClientDto>(insert); } [Authorize(Permissions.IDManagementPermissions.Clients.Delete)] public async Task DeleteAsync(Guid id) { var client = await _clientRepository.FindAsync(id); if (client != null) { await _clientRepository.DeleteAsync(client); } else throw new BusinessException(ExceptionCodes.ClientNotFound).WithData("0", id); } public async Task<ClientDto> GetAsync(Guid id) { var client = await _clientRepository.FindAsync(id); if (client == null) throw new BusinessException(Liujb.Shared.ExceptionCodes.ClientNotFound).WithData("0",id); return ObjectMapper.Map<Client, ClientDto>(client); } public async Task<PagedResultDto<ClientDto>> GetListAsync(GetClientsInputDto input) { var count = await _clientRepository.GetCountAsync(); var list = await _clientRepository.GetPagedListAsync(input.SkipCount, input.MaxResultCount, "CreationTime asc", true); var retList = ObjectMapper.Map<List<Client>, List<ClientDto>>(list); PagedResultDto<ClientDto> ret = new PagedResultDto<ClientDto>() { Items = retList, TotalCount = count }; return ret; } public async Task<string[]> GetScopesAsync() { var listIdentity = (await _identityResourceRepository.GetListAsync()).Select(r => r.Name).ToList(); var listApi = (await _apiResourceRepository.GetListAsync(true)).Select(r => r.Name).ToList(); listIdentity.AddRange(listApi); return listIdentity.ToArray(); } [Authorize(Permissions.IDManagementPermissions.Clients.Update)] public async Task<ClientDto> UpdateAsync(Guid id, UpdateClientDto input) { var client =await _clientRepository.GetAsync(id,true); if (client == null) throw new BusinessException(ExceptionCodes.ClientNotFound).WithData("0", id); ObjectMapper.Map<UpdateClientDto, Client>(input, client); client.ClientSecrets = new List<ClientSecret>(); client.RemoveAllScopes(); await _clientRepository.UpdateAsync(client, true); await UpdateClientExaAsync(client: client, input.AllowedScopes, input.GrantTypes, input.RedirectUris, input.PostLogoutRedirectUris, null); return ObjectMapper.Map<Client, ClientDto>(client); } public async Task<bool> UpdatePasswordAsync(Guid id, string secret) { var client = await _clientRepository.GetAsync(id,true); if(client==null) throw new BusinessException(ExceptionCodes.ClientNotFound).WithData("0", id); if (string.IsNullOrEmpty(secret)) throw new ArgumentNullException(); client.ClientSecrets = new List<ClientSecret>(); await _clientRepository.UpdateAsync(client,true); client.AddSecret(secret.Sha256()); await _clientRepository.UpdateAsync(client); return true; } private async Task<Client> UpdateClientExaAsync( Client client, IEnumerable<string> scopes, IEnumerable<string> grantTypes, IEnumerable<string> redirectUris = null, IEnumerable<string> postLogoutRedirectUris = null, string secret = null ) { foreach (var scope in scopes) { if (client.FindScope(scope) == null) { client.AddScope(scope); } } foreach (var grantType in grantTypes) { if (client.FindGrantType(grantType) == null) { client.AddGrantType(grantType); } } if (!secret.IsNullOrEmpty()) { if (client.FindSecret(secret) == null) { client.AddSecret(secret.Sha256()); } } if (redirectUris != null) { redirectUris.ToList().ForEach(redirectUri => { if (client.FindRedirectUri(redirectUri) == null) { client.AddRedirectUri(redirectUri); } }); } if (postLogoutRedirectUris != null) { postLogoutRedirectUris.ToList().ForEach(postLogoutRedirectUri => { if (client.FindPostLogoutRedirectUri(postLogoutRedirectUri) == null) { client.AddPostLogoutRedirectUri(postLogoutRedirectUri); } }); } return await _clientRepository.UpdateAsync(client); } }
其中用到的Automapper配置类
public IDManagementIdentitysServerAutoMapperProfile() { CreateMap<CreateOrUpdateClientBaseDto, Client>(MemberList.Source); CreateMap<Volo.Abp.IdentityServer.Clients.Client, ClientDto>() .ForMember(d => d.RedirectUris, opt => opt.MapFrom(src => src.RedirectUris.Select(r => r.RedirectUri))) .ForMember(d => d.PostLogoutRedirectUris, opt => opt.MapFrom(src => src.PostLogoutRedirectUris.Select(r => r.PostLogoutRedirectUri))) .ForMember(d => d.AllowedScopes, opt => opt.MapFrom(src => src.AllowedScopes.Select(r => r.Scope))) .ForMember(d => d.GrantTypes, opt => opt.MapFrom(src => src.AllowedGrantTypes.Select(r => r.GrantType))) ; CreateMap<Volo.Abp.IdentityServer.ApiResources.ApiResource, ApiResourceDto>().ForMember(src=>src.Claims, opt=>opt.MapFrom(src=>src.UserClaims.ToList().Select(r=>r.Type).ToList())); CreateMap<IdentityResource, IdentityResourceDto>().ForMember(src => src.Claims, opt => opt.MapFrom(src => src.UserClaims.ToList().Select(r => r.Type).ToList())); }
3,暴露服务接口
4,添加相关页面
五,添加权限
public class IDManagementPermissions { public const string GroupName = "IDManagement"; public static class IdentityResource { public const string Defalut = GroupName + ".IdentityResource"; public const string Create = Defalut + ".Create"; public const string Update = Defalut + ".Update"; public const string Delete = Defalut + ".Delete"; } public static class ApiResource { public const string Defalut = GroupName + ".ApiResource"; public const string Create = Defalut + ".Create"; public const string Update = Defalut + ".Update"; public const string Delete = Defalut + ".Delete"; } public static class Clients { public const string Defalut = GroupName+".Clients"; public const string Create = Defalut + ".Create"; public const string Update = Defalut + ".Update"; public const string Delete = Defalut + ".Delete"; } public static class Claims { public const string Defalut = GroupName + ".Claims"; public const string Create = Defalut + ".Create"; public const string Update = Defalut + ".Update"; public const string Delete = Defalut + ".Delete"; } public static string[] GetAll() { return ReflectionHelper.GetPublicConstantsRecursively(typeof(IDManagementPermissions)); } } public override void Define(IPermissionDefinitionContext context) { var clientGroup = context.AddGroup(IDManagementPermissions.GroupName, L("Permission:IDManagement")); var client=clientGroup.AddPermission(IDManagementPermissions.Clients.Defalut, L("Permission:Clients"), Volo.Abp.MultiTenancy.MultiTenancySides.Host); client.AddChild(IDManagementPermissions.Clients.Create, L("Permission:Create"), Volo.Abp.MultiTenancy.MultiTenancySides.Host); client.AddChild(IDManagementPermissions.Clients.Delete, L("Permission:Delete"), Volo.Abp.MultiTenancy.MultiTenancySides.Host); client.AddChild(IDManagementPermissions.Clients.Update, L("Permission:Edit"), Volo.Abp.MultiTenancy.MultiTenancySides.Host); var api = clientGroup.AddPermission(IDManagementPermissions.ApiResource.Defalut, L("Permission:Apis"), Volo.Abp.MultiTenancy.MultiTenancySides.Host); api.AddChild(IDManagementPermissions.ApiResource.Create, L("Permission:Create"), Volo.Abp.MultiTenancy.MultiTenancySides.Host); api.AddChild(IDManagementPermissions.ApiResource.Delete, L("Permission:Delete"), Volo.Abp.MultiTenancy.MultiTenancySides.Host); api.AddChild(IDManagementPermissions.ApiResource.Update, L("Permission:Edit"), Volo.Abp.MultiTenancy.MultiTenancySides.Host); var ids = clientGroup.AddPermission(IDManagementPermissions.IdentityResource.Defalut, L("Permission:Ids"), Volo.Abp.MultiTenancy.MultiTenancySides.Host); ids.AddChild(IDManagementPermissions.IdentityResource.Create, L("Permission:Create"), Volo.Abp.MultiTenancy.MultiTenancySides.Host); ids.AddChild(IDManagementPermissions.IdentityResource.Delete, L("Permission:Delete"), Volo.Abp.MultiTenancy.MultiTenancySides.Host); ids.AddChild(IDManagementPermissions.IdentityResource.Update, L("Permission:Edit"), Volo.Abp.MultiTenancy.MultiTenancySides.Host); var claims = clientGroup.AddPermission(IDManagementPermissions.Claims.Defalut, L("Permission:Claims"), Volo.Abp.MultiTenancy.MultiTenancySides.Host); claims.AddChild(IDManagementPermissions.Claims.Create, L("Permission:Create"), Volo.Abp.MultiTenancy.MultiTenancySides.Host); claims.AddChild(IDManagementPermissions.Claims.Delete, L("Permission:Delete"), Volo.Abp.MultiTenancy.MultiTenancySides.Host); claims.AddChild(IDManagementPermissions.Claims.Update, L("Permission:Edit"), Volo.Abp.MultiTenancy.MultiTenancySides.Host); } private static LocalizableString L(string name) { return LocalizableString.Create<Kingsun.Liujb.Shared.KingsunLiujbSharedResource>(name); //LocalizableString.Create<IDManagementResource>(name); } }
六,添加菜单
public class IDManagementMenus { public const string Prefix = "IDManagement"; //Add your menu items here... //public const string Home = Prefix + ".MyNewMenuItem"; public const string Claims = Prefix + ".Claims"; public const string Clients = Prefix + ".Clients"; public const string ApiResources = Prefix + ".ApiResources"; public const string IdentityResources = Prefix + ".IdentityResources"; } private async Task ConfigureMainMenu(MenuConfigurationContext context) { //Add main menu items. bool hasClaimsPermission = await context.IsGrantedAsync(Permissions.IDManagementPermissions.Claims.Defalut); bool hasClientsPermission = await context.IsGrantedAsync(Permissions.IDManagementPermissions.Clients.Defalut); bool hasApiResourcesPermission = await context.IsGrantedAsync(Permissions.IDManagementPermissions.ApiResource.Defalut); bool hasIdentityResourcePermission = await context.IsGrantedAsync(Permissions.IDManagementPermissions.IdentityResource.Defalut); var adminMenu = context.Menu.GetAdministration(); var L = context.GetLocalizer<Localization.IDManagementResource>(); if (hasClaimsPermission || hasApiResourcesPermission || hasClientsPermission || hasIdentityResourcePermission) { var group = new ApplicationMenuItem(IDManagementMenus.Prefix, L["Permission:IDManagement"], icon: "fa fa-id-card-o"); if (hasClaimsPermission) { group.AddItem(new ApplicationMenuItem(IDManagementMenus.Claims,L["Permission:Claims"], icon: "fa fa-id-card-o",url:"~/Claims")); } if (hasClientsPermission) { group.AddItem(new ApplicationMenuItem(IDManagementMenus.Clients, L["Permission:Clients"], icon: "fa fa-id-card-o", url: "~/Clients")); } if (hasApiResourcesPermission) { group.AddItem(new ApplicationMenuItem(IDManagementMenus.ApiResources, L["Permission:Apis"], icon: "fa fa-id-card-o", url: "~/Apis")); } if (hasIdentityResourcePermission) { group.AddItem(new ApplicationMenuItem(IDManagementMenus.IdentityResources, L["Permission:Ids"], icon: "fa fa-id-card-o", url: "~/Ids")); } adminMenu.AddItem(group); } }
七,统一本地化资源管理
public static class ExceptionCodes { public const string ClientNotFound = "Kingsun.Liujb:0001"; public const string ClientAreadyFound = "Kingsun.Liujb:0002"; public const string ApiResourceNotFound = "Kingsun.Liujb:0003"; public const string ApiResourceAreadyFound = "Kingsun.Liujb:0004"; public const string IdentityResourceNotFound = "Kingsun.Liujb:0005"; public const string IdentityResourceAreadyFound = "Kingsun.Liujb:0006"; public const string ClaimNotFound = "Kingsun.Liujb:0007"; public const string ClaimAreadyFound = "Kingsun.Liujb:0008"; public const string CanNotDeleteAStaticClaim = "Kingsun.Liujb:0009"; } [DependsOn(typeof(AbpLocalizationModule))] public class KingsunLiujbSharedModule:AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) { Configure<AbpVirtualFileSystemOptions>(options => { options.FileSets.AddEmbedded<KingsunLiujbSharedModule>("Kingsun.Liujb.Shared"); }); Configure<AbpLocalizationOptions>(options => { options.Resources .Add<KingsunLiujbSharedResource>("en") .AddBaseTypes(typeof(DefaultResource)) .AddVirtualJson("/Localization/KingsunLiujbShared"); }); } }
在Domain.Share包中Module类中使用统一资源
Configure<AbpLocalizationOptions>(options => { options.Resources .Add<IDManagementResource>("en") .AddBaseTypes(typeof(AbpValidationResource) ,typeof(Shared.KingsunLiujbSharedResource) ) .AddVirtualJson("/Localization/IDManagement"); }); Configure<AbpExceptionLocalizationOptions>(options => { options.MapCodeNamespace("Kingsun.Liujb.IDManagement", typeof(IDManagementResource)); options.MapCodeNamespace("Kingsun.Liujb", typeof(IDManagementResource)); });
八,验证客户端
1,使用密码模式获取token
2,使用Token随便访问一个api