Skip to content

Additional Feature Implementing server side IsInRole and client side hasRole

Victor Tomaili edited this page May 3, 2021 · 1 revision

Server Side - IsInRole

UserRoleRow.cs

public sealed class UserRoleRow : Row, IIdRow
{
   ...

    [DisplayName("Role Id"), NotNull, ForeignKey("Roles", "RoleId"), LeftJoin("jRole")] //<===---
    public Int32? RoleId
    {
        get { return Fields.RoleId[this]; }
        set { Fields.RoleId[this] = value; }
    }
   ...

    [DisplayName("Role Name"), Expression("jRole.[RoleName]")]
    public String RoleName
    {
        get { return Fields.RoleName[this]; }
        set { Fields.RoleName[this] = value; }
    }
    ...

    public class RowFields : RowFieldsBase
    {
       ...
        public StringField RoleName;
    }
}

UserDefinition.cs

using Serenity;
using System;
using System.Collections.Generic;
using System.Linq;
using Core.Constant;

[Serializable]
public class UserDefinition : IUserDefinition
{
	public string Id { get { return UserId.ToInvariant(); } }
	public string DisplayName { get; set; }
	public string Email { get; set; }
	public string UserImage { get; set; }
	public short IsActive { get; set; }
	public int UserId { get; set; }
	public string Username { get; set; }
	public string PasswordHash { get; set; }
	public string PasswordSalt { get; set; }
	public string Source { get; set; }
	public DateTime? UpdateDate { get; set; }
	public DateTime? LastDirectoryUpdate { get; set; }
	public List<RoleDefinition> Roles { get; set; }           //<===---
}

[Serializable]
public class RoleDefinition                                       //<===---
{
	public int RoleId { get; set; }
	public string RoleName { get; set; }
}

UserDefinitionExtension.cs

using System.Linq;

public static class UserDefinitionExtension
{
    public static bool IsInRole(this UserDefinition userDefinition, string roleName)
    {
        return userDefinition.Roles.Any(r => r.RoleName == roleName);
    }

    public static bool IsInRole(this UserDefinition userDefinition, int roleId)
    {
        return userDefinition.Roles.Any(r => r.RoleId == roleId);
    }
}

UserRetrieveService.cs

private UserDefinition GetFirst(IDbConnection connection, BaseCriteria criteria)
{
    var user = connection.TrySingle<Entities.UserRow>(criteria);
    if (user != null)
        return new UserDefinition
        {
            UserId = user.UserId.Value,
            Username = user.Username,
            Email = user.Email,
            UserImage = user.UserImage,
            DisplayName = user.DisplayName,
            IsActive = user.IsActive.Value,
            Source = user.Source,
            PasswordHash = user.PasswordHash,
            PasswordSalt = user.PasswordSalt,
            UpdateDate = user.UpdateDate,
            LastDirectoryUpdate = user.LastDirectoryUpdate,
            Roles = GetUserRoles(connection, user.UserId.Value)           //<===----
        };

    return null;
}

private List<RoleDefinition> GetUserRoles(IDbConnection connection, int userId)           //<===----
{
    var fld = Entities.UserRoleRow.Fields;
    var userRoles = connection.List<Entities.UserRoleRow>((query) => {
        query.SelectTableFields()
            .Select(fld.RoleName)
            .Where(new Criteria(fld.UserId) == userId);
    });

    var roles = new List<RoleDefinition>();

    userRoles.ForEach(r => {
        roles.Add(new RoleDefinition() {
            RoleId = r.RoleId.Value,
            RoleName = r.RoleName
        });
    });

    return roles;
}

Usage

var user = (UserDefinition)Authorization.UserDefinition.
var hasRole = user.IsInRole("RoleName");
// Or 
var hasRole = user.IsInRole(1); //RoleId

Client Side - hasRole

ScriptUserDefinition.cs

[ScriptInclude]
public class ScriptUserDefinition
{
    public String Username { get; set; }
    public String DisplayName { get; set; }
    public Boolean IsAdmin { get; set; }
    public Dictionary<string, bool> Permissions { get; set; }
    public List<string> Roles { get; set; }  //<===---
}

UserEndpoint.cs

[NonAction, DataScript("UserData", CacheDuration = -1), ServiceAuthorize]
public ScriptUserDefinition GetUserData()
{
    var result = new ScriptUserDefinition();
    var user = Authorization.UserDefinition as UserDefinition;

    if (user == null)
    {
        result.Permissions = new Dictionary<string, bool>();
        return result;
    }

    result.Username = user.Username;
    result.DisplayName = user.DisplayName;
    result.IsAdmin = user.Username == "admin";

    result.Permissions = TwoLevelCache.GetLocalStoreOnly("ScriptUserPermissions:" + user.Id, TimeSpan.Zero,
        UserPermissionRow.Fields.GenerationKey, () =>
        {
            var permissions = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase);

            if (permissionsUsedFromScript == null)
            {
                permissionsUsedFromScript = new UserPermissionRepository().ListPermissionKeys().Entities
                    .Where(permissionKey =>
                    {
                        // this sends permission information for all permission keys to client side.
                        // if you don't need all of them to be available from script, filter them here.
                        // this is recommended for security / performance reasons...
                        return true;
                    }).ToArray();
            }

            foreach (var permissionKey in permissionsUsedFromScript)
            {
                if (Authorization.HasPermission(permissionKey))
                    permissions[permissionKey] = true;
            }

            return permissions;
        });
    result.Roles = user.Roles.Select(r => r.RoleName).ToList();   //<===---
    return result;
}

Build and run T4 templates

Authorization.ts

namespace MyProject.Authorization {
    export declare let userDefinition: ScriptUserDefinition;

    Object.defineProperty(Authorization, 'userDefinition', {
        get: function () {
            return Q.getRemoteData('UserData');
        }
    });

    export function hasPermission(permissionKey: string): boolean {
        let ud = userDefinition;
        return ud.Username === 'admin' || !!ud.Permissions[permissionKey];
    }

    export function hasRole(roleName: string): boolean {                            //<===---
        let ud = userDefinition;
        return ud.Username === 'admin' || Q.indexOf(ud.Roles, r => r === roleName) >= 0;
    }
}

Usage

Authorization.hasRole('RoleName');
Clone this wiki locally