Skip to main content

Access the Currently Logged User for Data Filtering, Business Logic, and Security Permissions

  • 5 minutes to read

An application’s functionality may depend on the user who is logged on. You may need to obtain the user name, user ID, or entire user object. This topic describes how to do that in popular scenarios.

In .NET Applications

The following help topics describe how to use Dependency Injection to access an object that stores information about the current user:

In .NET Framework Applications

In .NET Framework Applications, you can use the following static properties exposed by the SecuritySystem class to access information about the current user:

Note

ASP.NET classes (MVC controllers, Razor components) and Web API controllers cannot use these static properties.

Access Current User in Criteria

Use the CurrentUserId function criteria operator to access the current user in a filter criterion.

Initialize the Object Owner (CreatedBy, UpdatedBy Properties)

To assign the current user reference to the CreatedBy and UpdatedBy properties of your business class, inherit your business class from BaseObject and override the OnSaving method. To set the property values, call the BaseObject.SetPropertyValueWithSecurityBypass method. This method allows you to modify the value of a business object’s property even if write access to this property is denied for the current user by the XAF Security System.

Important

CreatedBy, UpdatedBy, UpdatedOn, CreatedOn, and similar properties are supposed to be read-only in the UI for security and audit reasons (they can only be modified by developers in the program code). To make these properties read-only, set the AllowEdit setting to false for these properties through data annotation attributes (ModelDefault, Browsable, VisibleInXXX). Depending on your security and UI customization requirements, you may want to add additional constraints. You can make sure that end users cannot display these properties or their sub-fields in the UI. To accomplish this, do the following:

The following code snippet demonstrates how to initialize a business object’s CreatedBy and UpdatedBy properties:

File: MySolution.Module/BusinessObjects/TestClass.cs

using DevExpress.ExpressApp.Model;
using DevExpress.ExpressApp.Security;
using DevExpress.Persistent.Base;
using DevExpress.Persistent.BaseImpl.EF;
using Microsoft.Extensions.DependencyInjection;
// ...
public class TestClass : BaseObject {
    // ...
    [ModelDefault(nameof(IModelCommonMemberViewItem.AllowEdit), "False")]
    public virtual ApplicationUser CreatedBy { get; set; }
    [ModelDefault(nameof(IModelCommonMemberViewItem.AllowEdit), "False")]
    public virtual ApplicationUser UpdatedBy { get; set; }

    ApplicationUser GetCurrentUser() {
        return ObjectSpace.GetObjectByKey<ApplicationUser>(
            ObjectSpace.ServiceProvider.GetRequiredService<ISecurityStrategyBase>().UserId);
    }

    public override void OnSaving() {
        base.OnSaving();
        if (ObjectSpace.IsNewObject(this)) {
            SetPropertyValueWithSecurityBypass(nameof(CreatedBy), GetCurrentUser());
        }
        else {
            SetPropertyValueWithSecurityBypass(nameof(UpdatedBy), GetCurrentUser());
        }
    }
} 

Initialize the Object Owner - Middle-Tier Security Specifics

In applications with middle-tier security, you need to take the following additional considerations into account:

  • A business object’s OnCreated and AfterConstruction methods are called on the client side, so property values initialized by these methods are available to the client application. Because of this, it is not secure to use these methods to initialize properties that store sensitive data (CreatedBy, UpdatedBy, and so on).
  • In cases when you need to initialize properties that store sensitive data, we strongly recommend that you always use the OnSaving method. This method is secure because it is called on the middle-tier server side only.
  • In applications with middle tier security, the BaseObject.SetPropertyValueWithSecurityBypass method can only be called from the OnSaving method. Otherwise, an exception is thrown.

Configure Permissions Based on the Object Owner

To grant access to objects that are owned by the current user and prohibit access to other objects, implement the CreatedBy property as demonstrated above, and configure the security permissions as follows:

  • Add a Type Permission for the object type you wish to filter and set its ReadState property to Deny or leave it empty if the role’s Permission Policy is DenyAllByDefault.
  • Add an Object Permission that allows reading objects whose owner user’s ID matches CurrentUserId().

File: MySolution.Module/DatabaseUpdate/Updater.cs

using DevExpress.ExpressApp.Security;
using DevExpress.ExpressApp.SystemModule;
// ...
defaultRole.AddTypePermission<TestClass>(SecurityOperations.Read, SecurityPermissionState.Deny);
defaultRole.AddObjectPermissionFromLambda<TestClass>(
    SecurityOperations.Read, 
    e => e.CreatedBy.ID == (Guid)CurrentUserIdOperator.CurrentUserId(), 
    SecurityPermissionState.Allow
);
// or
// userRole.AddObjectPermission<Note>(SecurityOperations.Read, 
//     "CreatedBy.ID = CurrentUserId()", SecurityPermissionState.Allow);

For more information, refer to Create Predefined Users, Roles and Permissions in the Database.

To try the described technique in your application and add several users, run the application and create an object of your business class under different user accounts - only the currently logged-in user’s objects are displayed in the List View:

Result

The following example implements a more complex use case scenario with cascading owner objects:

View Example: How to restrict inter-departmental data access using Security Permissions

Check Security Permissions in Code

The following help topic describes how to check if a user has a specific role or permission to perform a certain operation: Determine if the Current User Has Specific Permissions.

See Also