using Nop.Core; using Nop.Core.Caching; using Nop.Core.Domain.Customers; using Nop.Core.Domain.Security; using Nop.Core.Infrastructure; using Nop.Data; using Nop.Services.Customers; using Nop.Services.Localization; namespace Nop.Services.Security; /// /// Permission service /// public partial class PermissionService : IPermissionService { #region Fields protected readonly ICustomerService _customerService; protected readonly ILocalizationService _localizationService; protected readonly IRepository _customerRoleRepository; protected readonly IRepository _permissionRecordRepository; protected readonly IRepository _permissionRecordCustomerRoleMappingRepository; protected readonly IStaticCacheManager _staticCacheManager; protected readonly ITypeFinder _typeFinder; protected readonly IWorkContext _workContext; #endregion #region Ctor public PermissionService(ICustomerService customerService, ILocalizationService localizationService, IRepository customerRoleRepository, IRepository permissionRecordRepository, IRepository permissionRecordCustomerRoleMappingRepository, IStaticCacheManager staticCacheManager, ITypeFinder typeFinder, IWorkContext workContext) { _customerService = customerService; _localizationService = localizationService; _customerRoleRepository = customerRoleRepository; _permissionRecordRepository = permissionRecordRepository; _permissionRecordCustomerRoleMappingRepository = permissionRecordCustomerRoleMappingRepository; _staticCacheManager = staticCacheManager; _typeFinder = typeFinder; _workContext = workContext; } #endregion #region Utilities /// /// Get permission records by customer role identifier /// /// Customer role identifier /// /// A task that represents the asynchronous operation /// The task result contains the permissions /// protected virtual async Task> GetPermissionRecordsByCustomerRoleIdAsync(int customerRoleId) { var key = _staticCacheManager.PrepareKeyForDefaultCache(NopSecurityDefaults.PermissionRecordsAllCacheKey, customerRoleId); var query = from pr in _permissionRecordRepository.Table join prcrm in _permissionRecordCustomerRoleMappingRepository.Table on pr.Id equals prcrm .PermissionRecordId where prcrm.CustomerRoleId == customerRoleId orderby pr.Id select pr; return await _staticCacheManager.GetAsync(key, async () => await query.ToListAsync()); } /// /// Gets a permission /// /// Permission system name /// /// A task that represents the asynchronous operation /// The task result contains the permission /// protected virtual async Task GetPermissionRecordBySystemNameAsync(string systemName) { if (string.IsNullOrWhiteSpace(systemName)) return null; var query = from pr in _permissionRecordRepository.Table where pr.SystemName == systemName orderby pr.Id select pr; var permissionRecord = await query.FirstOrDefaultAsync(); return permissionRecord; } /// /// Insert permissions by list of permission configs /// /// Permission configs /// A task that represents the asynchronous operation protected virtual async Task InstallPermissionsAsync(IList configs) { if (!configs?.Any() ?? true) return; var exists = await _permissionRecordCustomerRoleMappingRepository.GetAllAsync(query => query, getCacheKey: _ => default); async Task addPermissionRecordCustomerRoleMappingIfNotExists( PermissionRecordCustomerRoleMapping permissionRecordCustomerRoleMapping) { var mapping = exists.FirstOrDefault(m => m.CustomerRoleId == permissionRecordCustomerRoleMapping.CustomerRoleId && m.PermissionRecordId == permissionRecordCustomerRoleMapping.PermissionRecordId); if (mapping != null) { permissionRecordCustomerRoleMapping.Id = mapping.Id; return; } await _permissionRecordCustomerRoleMappingRepository.InsertAsync(permissionRecordCustomerRoleMapping, false); exists.Add(permissionRecordCustomerRoleMapping); } foreach (var config in configs) { //new permission (install it) var permission = new PermissionRecord { Name = config.Name, SystemName = config.SystemName, Category = config.Category }; //save new permission await _permissionRecordRepository.InsertAsync(permission); foreach (var systemRoleName in config.DefaultCustomerRoles) { var customerRole = await GetCustomerRoleBySystemNameAsync(systemRoleName); if (customerRole == null) { //new role (save it) customerRole = new CustomerRole { Name = systemRoleName, Active = true, SystemName = systemRoleName }; await _customerRoleRepository.InsertAsync(customerRole); } await addPermissionRecordCustomerRoleMappingIfNotExists(new PermissionRecordCustomerRoleMapping { CustomerRoleId = customerRole.Id, PermissionRecordId = permission.Id }); } //save localization await _localizationService.SaveLocalizedPermissionNameAsync(permission); } } /// /// Gets a customer role /// /// Customer role system name /// /// A task that represents the asynchronous operation /// The task result contains the customer role /// protected virtual async Task GetCustomerRoleBySystemNameAsync(string systemName) { if (string.IsNullOrWhiteSpace(systemName)) return null; var key = _staticCacheManager.PrepareKeyForDefaultCache(NopCustomerServicesDefaults.CustomerRolesBySystemNameCacheKey, systemName); var query = from cr in _customerRoleRepository.Table orderby cr.Id where cr.SystemName == systemName select cr; var customerRole = await _staticCacheManager.GetAsync(key, async () => await query.FirstOrDefaultAsync()); return customerRole; } #endregion #region Methods /// /// Gets all permissions /// /// /// A task that represents the asynchronous operation /// The task result contains the permissions /// public virtual async Task> GetAllPermissionRecordsAsync() { var permissions = await _permissionRecordRepository.GetAllAsync(query => from pr in query orderby pr.Name select pr); return permissions; } /// /// Inserts a permission /// /// Permission /// A task that represents the asynchronous operation public virtual async Task InsertPermissionRecordAsync(PermissionRecord permission) { await _permissionRecordRepository.InsertAsync(permission); } /// /// Gets a permission record by identifier /// /// Permission identifier /// /// A task that represents the asynchronous operation /// The task result contains a permission record /// public virtual async Task GetPermissionRecordByIdAsync(int permissionId) { return await _permissionRecordRepository.GetByIdAsync(permissionId); } /// /// Updates the permission /// /// Permission /// A task that represents the asynchronous operation public virtual async Task UpdatePermissionRecordAsync(PermissionRecord permission) { await _permissionRecordRepository.UpdateAsync(permission); } /// /// Delete a permission /// /// Permission /// A task that represents the asynchronous operation public virtual async Task DeletePermissionRecordAsync(PermissionRecord permission) { await _permissionRecordRepository.DeleteAsync(permission); } /// /// Delete a permission /// /// Permission system name /// A task that represents the asynchronous operation public virtual async Task DeletePermissionAsync(string permissionSystemName) { var permission = await GetPermissionRecordBySystemNameAsync(permissionSystemName); if (permission == null) return; var mapping = await GetMappingByPermissionRecordIdAsync(permission.Id); await _permissionRecordCustomerRoleMappingRepository.DeleteAsync(mapping); await _localizationService.DeleteLocalizedPermissionNameAsync(permission); await _permissionRecordRepository.DeleteAsync(permission); } /// /// Authorize permission /// /// Permission record /// /// A task that represents the asynchronous operation /// The task result contains the true - authorized; otherwise, false /// public virtual async Task AuthorizeAsync(PermissionRecord permission) { return await AuthorizeAsync(permission, await _workContext.GetCurrentCustomerAsync()); } /// /// Authorize permission /// /// Permission record /// Customer /// /// A task that represents the asynchronous operation /// The task result contains the true - authorized; otherwise, false /// public virtual async Task AuthorizeAsync(PermissionRecord permission, Customer customer) { if (permission == null) return false; if (customer == null) return false; return await AuthorizeAsync(permission.SystemName, customer); } /// /// Authorize permission /// /// Permission record system name /// /// A task that represents the asynchronous operation /// The task result contains the true - authorized; otherwise, false /// public virtual async Task AuthorizeAsync(string permissionRecordSystemName) { return await AuthorizeAsync(permissionRecordSystemName, await _workContext.GetCurrentCustomerAsync()); } /// /// Authorize permission /// /// Permission record system name /// Customer /// /// A task that represents the asynchronous operation /// The task result contains the true - authorized; otherwise, false /// public virtual async Task AuthorizeAsync(string permissionRecordSystemName, Customer customer) { if (string.IsNullOrEmpty(permissionRecordSystemName)) return false; var customerRoles = await _customerService.GetCustomerRolesAsync(customer); foreach (var role in customerRoles) if (await AuthorizeAsync(permissionRecordSystemName, role.Id)) //yes, we have such permission return true; //no permission found return false; } /// /// Authorize permission /// /// Permission record system name /// Customer role identifier /// /// A task that represents the asynchronous operation /// The task result contains the true - authorized; otherwise, false /// public virtual async Task AuthorizeAsync(string permissionRecordSystemName, int customerRoleId) { if (string.IsNullOrEmpty(permissionRecordSystemName)) return false; var key = _staticCacheManager.PrepareKeyForDefaultCache(NopSecurityDefaults.PermissionAllowedCacheKey, permissionRecordSystemName, customerRoleId); return await _staticCacheManager.GetAsync(key, async () => { var permissions = await GetPermissionRecordsByCustomerRoleIdAsync(customerRoleId); foreach (var permission in permissions) if (permission.SystemName.Equals(permissionRecordSystemName, StringComparison.InvariantCultureIgnoreCase)) return true; return false; }); } /// /// Gets a permission record-customer role mapping /// /// Permission identifier /// /// A task that represents the asynchronous operation /// The task result contains a list of mappings /// public virtual async Task> GetMappingByPermissionRecordIdAsync(int permissionId) { var query = _permissionRecordCustomerRoleMappingRepository.Table; query = query.Where(x => x.PermissionRecordId == permissionId); return await query.ToListAsync(); } /// /// Delete a permission record-customer role mapping /// /// Permission identifier /// Customer role identifier /// A task that represents the asynchronous operation public virtual async Task DeletePermissionRecordCustomerRoleMappingAsync(int permissionId, int customerRoleId) { var mapping = await _permissionRecordCustomerRoleMappingRepository.Table .FirstOrDefaultAsync(prcm => prcm.CustomerRoleId == customerRoleId && prcm.PermissionRecordId == permissionId); if (mapping is null) return; await _permissionRecordCustomerRoleMappingRepository.DeleteAsync(mapping); } /// /// Inserts a permission record-customer role mapping /// /// Permission record-customer role mapping /// A task that represents the asynchronous operation public virtual async Task InsertPermissionRecordCustomerRoleMappingAsync(PermissionRecordCustomerRoleMapping permissionRecordCustomerRoleMapping) { await _permissionRecordCustomerRoleMappingRepository.InsertAsync(permissionRecordCustomerRoleMapping); } /// /// Configure permission manager /// /// A task that represents the asynchronous operation public virtual async Task InsertPermissionsAsync() { var permissionRecords = (await _permissionRecordRepository.GetAllAsync(query => query, getCacheKey: _ => null)).Distinct().ToHashSet(); var exists = permissionRecords.Select(p => p.SystemName).ToHashSet(); var configs = _typeFinder.FindClassesOfType() .Select(configType => (IPermissionConfigManager)Activator.CreateInstance(configType)) .SelectMany(config => config?.AllConfigs ?? new List()) .Where(c => !exists.Contains(c.SystemName)) .ToList(); await InstallPermissionsAsync(configs); } /// /// Inserts a permission record-customer role mappings /// /// Customer role ID /// Permissions /// A task that represents the asynchronous operation public virtual async Task InsertPermissionMappingAsync(int customerRoleId, params string[] permissions) { var permissionRecords = await GetAllPermissionRecordsAsync(); foreach (var permissionSystemName in permissions) { var permission = permissionRecords.FirstOrDefault(p => p.SystemName.Equals(permissionSystemName, StringComparison.CurrentCultureIgnoreCase)); if (permission == null) continue; await InsertPermissionRecordCustomerRoleMappingAsync( new PermissionRecordCustomerRoleMapping { CustomerRoleId = customerRoleId, PermissionRecordId = permission.Id }); } } #endregion }