Example E4483
Visible to All Users

XAF - How to implement a custom security operation that can be permitted at the type level

This example shows how to create a custom operation permission that allows you to prohibit the export operation when using the Security System.

image

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

EF/CustomPermissionEF/CustomPermissionEF.Module/Controllers/RemoveBaseTypePermissionNewActionItemController.cs
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(); } } }
EF/CustomPermissionEF/CustomPermissionEF.Blazor.Server/Startup.cs
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(); }); } }

Disclaimer: The information provided on DevExpress.com and affiliated web properties (including the DevExpress Support Center) is provided "as is" without warranty of any kind. Developer Express Inc disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.

Confidential Information: Developer Express Inc does not wish to receive, will not act to procure, nor will it solicit, confidential or proprietary materials and information from you through the DevExpress Support Center or its web properties. Any and all materials or information divulged during chats, email communications, online discussions, Support Center tickets, or made available to Developer Express Inc in any manner will be deemed NOT to be confidential by Developer Express Inc. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.