This example shows how to create a custom operation permission that allows you to prohibit the export operation when using the Security System.
Implementation Details
Refer to the following help topic for details: Implement a Custom Security Operation that Can be Permitted at the Type Level.
Files to Review
Documentation
Does this example address your development requirements/objectives?
(you will be redirected to DevExpress.com to submit your response)
Example Code
C#using CustomPermission.Module.Security;
using DevExpress.ExpressApp.SystemModule;
using DevExpress.ExpressApp;
using DevExpress.Persistent.BaseImpl.EF.PermissionPolicy;
namespace CustomPermission.Module.Controllers {
public class RemoveBaseTypePermissionNewActionItemController :
ObjectViewController<ObjectView, PermissionPolicyTypePermissionObject> {
protected override void OnFrameAssigned() {
NewObjectViewController newObjectViewController = Frame.GetController<NewObjectViewController>();
if (newObjectViewController != null) {
newObjectViewController.CollectDescendantTypes += (s, e) => {
e.Types.Remove(typeof(PermissionPolicyTypePermissionObject));
};
newObjectViewController.ObjectCreating += (s, e) => {
if (e.ObjectType == typeof(PermissionPolicyTypePermissionObject)) {
e.NewObject = e.ObjectSpace.CreateObject(typeof(CustomTypePermissionObject));
}
};
}
base.OnFrameAssigned();
}
}
}
C#using DevExpress.ExpressApp.Security;
using DevExpress.ExpressApp.ApplicationBuilder;
using DevExpress.ExpressApp.Blazor.ApplicationBuilder;
using DevExpress.ExpressApp.Blazor.Services;
using DevExpress.Persistent.Base;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Components.Server.Circuits;
using Microsoft.EntityFrameworkCore;
using CustomPermissionEF.Blazor.Server.Services;
using DevExpress.Persistent.BaseImpl.EF.PermissionPolicy;
using CustomPermission.Module.Security;
using CustomPermissionEF.Module.BusinessObjects;
namespace CustomPermissionEF.Blazor.Server;
public class Startup {
public Startup(IConfiguration configuration) {
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services) {
services.AddSingleton(typeof(Microsoft.AspNetCore.SignalR.HubConnectionHandler<>), typeof(ProxyHubConnectionHandler<>));
services.AddRazorPages();
services.AddServerSideBlazor();
services.AddHttpContextAccessor();
services.AddScoped<CircuitHandler, CircuitHandlerProxy>();
services.AddXaf(Configuration, builder => {
builder.UseApplication<CustomPermissionEFBlazorApplication>();
builder.Modules
.AddConditionalAppearance()
.AddValidation(options => {
options.AllowValidationDetailsAccess = false;
})
.Add<CustomPermissionEF.Module.CustomPermissionEFModule>()
.Add<CustomPermissionEFBlazorModule>();
builder.ObjectSpaceProviders
.AddSecuredEFCore(options => options.PreFetchReferenceProperties())
.WithDbContext<CustomPermissionEF.Module.BusinessObjects.CustomPermissionEFEFCoreDbContext>((serviceProvider, options) => {
// Uncomment this code to use an in-memory database. This database is recreated each time the server starts. With the in-memory database, you don't need to make a migration when the data model is changed.
// Do not use this code in production environment to avoid data loss.
// We recommend that you refer to the following help topic before you use an in-memory database: https://docs.microsoft.com/en-us/ef/core/testing/in-memory
//options.UseInMemoryDatabase("InMemory");
string connectionString = null;
if(Configuration.GetConnectionString("ConnectionString") != null) {
connectionString = Configuration.GetConnectionString("ConnectionString");
}
#if EASYTEST
if(Configuration.GetConnectionString("EasyTestConnectionString") != null) {
connectionString = Configuration.GetConnectionString("EasyTestConnectionString");
}
#endif
ArgumentNullException.ThrowIfNull(connectionString);
options.UseSqlServer(connectionString);
options.UseChangeTrackingProxies();
options.UseObjectSpaceLinkProxies();
options.UseXafServiceProviderContainer(serviceProvider);
options.UseLazyLoadingProxies();
})
.AddNonPersistent();
builder.Security
.UseIntegratedMode(options => {
options.RoleType = typeof(PermissionPolicyRole);
// ApplicationUser descends from PermissionPolicyUser and supports the OAuth authentication. For more information, refer to the following topic: https://docs.devexpress.com/eXpressAppFramework/402197
// If your application uses PermissionPolicyUser or a custom user type, set the UserType property as follows:
options.UserType = typeof(CustomPermissionEF.Module.BusinessObjects.ApplicationUser);
// ApplicationUserLoginInfo is only necessary for applications that use the ApplicationUser user type.
// If you use PermissionPolicyUser or a custom user type, comment out the following line:
options.UserLoginInfoType = typeof(CustomPermissionEF.Module.BusinessObjects.ApplicationUserLoginInfo);
options.Events.OnSecurityStrategyCreated += securityStrategy => {
// Use the 'PermissionsReloadMode.NoCache' option to load the most recent permissions from the database once
// for every DbContext instance when secured data is accessed through this instance for the first time.
// Use the 'PermissionsReloadMode.CacheOnFirstAccess' option to reduce the number of database queries.
// In this case, permission requests are loaded and cached when secured data is accessed for the first time
// and used until the current user logs out.
// See the following article for more details: https://docs.devexpress.com/eXpressAppFramework/DevExpress.ExpressApp.Security.SecurityStrategy.PermissionsReloadMode.
((SecurityStrategy)securityStrategy).PermissionsReloadMode = PermissionsReloadMode.NoCache;
((SecurityStrategy)securityStrategy).CustomizeRequestProcessors += delegate (object sender, CustomizeRequestProcessorsEventArgs e) {
List<IOperationPermission> result = new List<IOperationPermission>();
SecurityStrategyComplex security = sender as SecurityStrategyComplex;
if (security != null) {
ApplicationUser user = security.User as ApplicationUser;
if (user != null) {
foreach (PermissionPolicyRole role in user.Roles) {
foreach (PermissionPolicyTypePermissionObject persistentPermission in role.TypePermissions) {
CustomTypePermissionObject customPermission = persistentPermission as CustomTypePermissionObject;
if (customPermission != null && customPermission.ExportState != null) {
SecurityPermissionState state = (SecurityPermissionState)customPermission.ExportState;
result.Add(new ExportPermission(customPermission.TargetType, state));
}
}
}
}
}
IPermissionDictionary permissionDictionary = new PermissionDictionary(result);
e.Processors.Add(typeof(ExportPermissionRequest), new ExportPermissionRequestProcessor(permissionDictionary));
// ...
};
};
})
.AddPasswordAuthentication(options => {
options.IsSupportChangePassword = true;
});
});
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(options => {
options.LoginPath = "/LoginPage";
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
if(env.IsDevelopment()) {
app.UseDeveloperExceptionPage();
}
else {
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. To change this for production scenarios, see: https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseRequestLocalization();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseXaf();
app.UseEndpoints(endpoints => {
endpoints.MapXafEndpoints();
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
endpoints.MapControllers();
});
}
}