Base solution for your next web application
Open Closed

GetScripts Exception: There is no role with name: Administrator #9989


User avatar
0
carelearning created

Dear Support,

We are using the legacy .NET Framework 4.6.1 (MVC 5/Angular) version 6.1.1 with Single Deployment/Multiple Database

For our POST action in our AccountController for Login we want to currently limit authentication of users who have the role 'Administrator'.

Following the call to GetLoginResultAsync we have added this code:

    var isAdministrator = loginResult.Identity.Claims
        .Where(x => x.Type == ClaimTypes.Role)
        .Any(x => x.Value == Constants.Administrator);

    if (!isAdministrator)
        return Json(new AjaxResponse { Success = false, UnAuthorizedRequest = true, Error = new ErrorInfo(L("InvalidRole")) });

This works, however we noticed our Javascript side localization was missing. After investigating we discovered the call to http://localhost:5000/AbpScripts/GetScripts was failing with this exception:

    WARN 2021-01-13 11:37:58,042 [12 ] Abp.Logging.LogHelper - Abp.Authorization.AbpAuthorizationException: Current user did not login to the application!
    at Abp.Authorization.AuthorizationHelper.Authorize(IEnumerable`1 authorizeAttributes) 	 at Abp.Web.Mvc.Authorization.AbpMvcAuthorizeFilter.OnAuthorization(AuthorizationContext filterContext) 	Abp.Authorization.AbpAuthorizationException: Current user did not login to the application! 	 at Abp.Authorization.AuthorizationHelper.Authorize(IEnumerable`1 authorizeAttributes)
    at Abp.Web.Mvc.Authorization.AbpMvcAuthorizeFilter.OnAuthorization(AuthorizationContext filterContext)
    ERROR 2021-01-13 11:38:46,234 [15 ] Web.Mvc.Controllers.AbpScriptsController - There is no role with name: Administrator
    Abp.AbpException: There is no role with name: Administrator
    at Abp.Authorization.Roles.AbpRoleManager\`2.d\_\_59.MoveNext()
    \-\-\- End of stack trace from previous location where exception was thrown \-\-\-

In our AbpRoleManager class we overrode the GetRoleByNameAsync method with the following:

public override async Task<Role> GetRoleByNameAsync(string roleName)
{
    return await Task.FromResult(_roleRepository
        .GetAll()
        .SingleOrDefault(x => String.Equals(x.Name, roleName)));
}

All this works but we wanted to touch base and figure out why this was necessary.

Thanks!


4 Answer(s)
  • User Avatar
    0
    musa.demir created

    How did you add your Administrator role to application?


    By the way, current implementation throws an exception instead of returning new ajax response.

    https://github.com/aspnetzero/aspnet-zero-core/blob/438199372347db3404bf9ca8d28047ccfbe253ef/aspnet-core/src/MyCompanyName.AbpZeroTemplate.Web.Core/Controllers/TokenAuthController.cs#L743-L744

  • User Avatar
    0
    carelearning created

    Dear @musa.demir,

    Thank your for the reply. While developing this feature I manually added the Administrator role using the SQL Server Mangement Studio Edit Table feature. When I script the data from that table here is that record.

      SET IDENTITY_INSERT [dbo].[AbpRoles] ON 
      INSERT [dbo].[AbpRoles] ([Id], [TenantId], [Name], [DisplayName], [IsStatic], [IsDefault], [IsDeleted], [DeleterUserId], [DeletionTime], [LastModificationTime], [LastModifierUserId], [CreationTime], [CreatorUserId], [NormalizedName]) VALUES (1, 1, N'Administrator', N'Administrator', 1, 1, 0, NULL, NULL, NULL, NULL, CAST(N'2021-01-13T19:01:23.653' AS DateTime), NULL, N'ADMINISTRATOR')
      SET IDENTITY_INSERT [dbo].[AbpRoles] OFF
    

    I have since added the framework code, previously commented out by us, from the Entity Framework csproject for TenantDb seeding. That code looks like this:

      // Administrator role
      var adminRole = _context.Roles.FirstOrDefault(r => r.TenantId == _tenantId && r.Name == StaticRoleNames.Tenants.Administrator);
                if (adminRole == null)
                {
                    _context.Roles.Add(new Role(_tenantId, StaticRoleNames.Tenants.Administrator, StaticRoleNames.Tenants.Administrator) { IsStatic = true, IsDefault = true });
                    _context.SaveChanges();
                }
    

    I did alter the constant value from 'Admin' to 'Administrator'; here is that adjustment:

          public static class Tenants
          {
              public const string Administrator = "Administrator";
    
              public const string User = "User";
          }
    

    To assign I picked a known user and again used the SQL Management Studio Edit Table feature to populate the table data. In this instance the TenantId was 1, the UserId was 1 and the RoleId was 1 and the CreationTime was now. The equivalent T-SQL code to insert the record would like this:

         INSERT INTO AbpUserRoles (TenantId, UserId, RoleId, CreationTime) VALUES (1, 1, 1, GetUtcDate());
    
  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi @carelearning

    Is your app multi tenant ? I think GetRoleByNameAsync is executed with a TenantId value different than 1. Using a store is suggested approach by ASP.NET so end users can replace the store with an alternative but if using repository works for you, you can continue using it.

  • User Avatar
    0
    carelearning created

    @ismcagdas,

    Sorry for the late reply. Yes we are using multitenancy. Our work-around is okay we just questioned why we need to override the base class method GetRoleByNameAsync.

            public virtual async Task<TRole> GetRoleByNameAsync(string roleName)
                {
                    var role = await FindByNameAsync(roleName);
                    if (role == null)
                    {
                        throw new AbpException("There is no role with name: " + roleName);
                    }
    
                    return role;
                }
    

    with

        public override async Task<Role> GetRoleByNameAsync(string roleName)
        {
            return await Task.FromResult(_roleRepository
                .GetAll()
                .SingleOrDefault(x => String.Equals(x.Name, roleName)));
        }