Open Closed

Custom UserClaims #2144


0
bbakermmc created

Whats the best way to implement some custom user claims?

Im thinking I can create a new call in the Users AppService

public async Task CustomClaim(ProhibitPermissionInput input)
        {
            var user = await UserManager.GetUserByIdAsync(input.UserId);
            //var permission = _permissionManager.GetPermission(input.PermissionName);

            await UserManager.AddClaimAsync(input.UserId, new Claim("AllowedClients", "1,2,3"));

            //await UserManager.ProhibitPermissionAsync(user, permission);
        }

And then I think I need to modify something else to pull them out when they login correct?


13 Answer(s)
  • 0
    bbakermmc created

    UserAppService

    public async Task CustomClaim(CustomClaimInput input)
            {
                await UserManager.AddClaimAsync(input.UserId, new Claim(input.ClaimName, input.ClaimValue));
            }
    

    AccountController:

    private async Task SignInAsync(User user, ClaimsIdentity identity = null, bool rememberMe = false)
            {
                if (identity == null)
                {
                    identity = await _userManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
                }
                var claims = await _userManager.GetClaimsAsync(user.Id);
    
                foreach (var claim in claims)
                {
                    identity.AddClaim(new Claim(claim.Type, claim.Value));
                }
    
                AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
                AuthenticationManager.SignIn(new AuthenticationProperties { IsPersistent = rememberMe }, identity);
            }
    

    UsersLoginDTO

    ADD
    public ICollection<UserClaim> Claims { get; set; }
    
  • 0
    ismcagdas created
    Support Team

    Hi,

    You can check this issue <a class="postlink" href="https://github.com/aspnetboilerplate/module-zero/issues/63">https://github.com/aspnetboilerplate/mo ... /issues/63</a>.

  • 0
    pradippatil created

    Hi,

    I have added a custom claim in login post method as below:

    loginResult.Identity.AddClaim(new Claim("ParentUserId", Convert.ToString(user.ParentUserId)));
    

    I have also added a property in AspNetZeroAbpSession class as below:

    public long? ParentUserId
            {
                get
                {
                    var parentUserIdClaim = PrincipalAccessor.Principal?.Claims.FirstOrDefault(c => c.Type == "ParentUserId");
                    if (string.IsNullOrEmpty(parentUserIdClaim?.Value))
                    {
                        return null;
                    }
    
                    return Convert.ToInt64(parentUserIdClaim.Value);
                }
            }
    

    Now, I want to access this new property using AbpSession like AbpSession.ParentUserId, but I am not able to access it like that because IAbpSession interface does not have this new property. Is there any way to access this new property using AbpSession like AbpSession.ParentUserId?

    Thanks

  • 0
    ismcagdas created
    Support Team

    Hi,

    You cannot access it on AbpSession but you can create your own version like AbpSession and access it over your version. You can do it like in MyAppSession here <a class="postlink" href="https://gist.github.com/hikalkan/67469e05475c2d18cb88">https://gist.github.com/hikalkan/67469e05475c2d18cb88</a>

  • 0
    pradippatil created

    Thanks!

  • 0
    pradippatil created

    Hi,

    I have added new properties in session as mentioned in my previous comment. (#2144@c5b10a0c-d398-45c3-b017-8cad6e9af9bc)

    Now, I want to use this new property in Unit Tests. Can you please help me to figure out how this new property can be used in Unit Tests?

    Thanks

  • 0
    ismcagdas created
    Support Team

    Hi,

    You can create a new instance using Resolve<YourAbpSession> and set the property value according to your needs before running your tests.

    If the value of this property is same for all tests, you can do it in the AppTestBase's constructor.

  • 0
    pradippatil created

    I have added a property in application services base class as below:

    public abstract class GodseyPrecisionAgAppServiceBase : ApplicationService
        {
            public GPASession GPASession { get; set; }
    

    I am using it in application services as below:

    public async Task<ListResultDto<RoleListDto>> GetRoles(GetRolesInput input)
            {
                var roles = await _roleManager
                    .Roles
                    .Where(r => r.OrgAdminUserId == GPASession.OrgAdminUserId)
                    .WhereIf(
                        !input.Permission.IsNullOrWhiteSpace(),
                        r => r.Permissions.Any(rp => rp.Name == input.Permission && rp.IsGranted)
                    )
                    .ToListAsync();
    
                return new ListResultDto<RoleListDto>(roles.MapTo<List<RoleListDto>>());
            }
    

    Now, when I tried to write unit tests for this method, GPASession.OrgAdminUserId property is always null, because it reads the value from Claim. So, I created one TestGPASession class as below:

    public class TestGPASession : ClaimsAbpSession
        {
            public ITenantIdAccessor TenantIdAccessor { get; set; }
    
            public TestGPASession(IMultiTenancyConfig multiTenancy)
                : base(multiTenancy)
            {
    
            }
    
            public long? ParentUserId { get; set; }
    
            public long? OrgAdminUserId { get; set; }
    
            public bool IsSuperAdmin { get; set; }
        }
    

    And done changes to use it in AppTestBase class as below:

    public abstract class AppTestBase : AbpIntegratedTestBase<GodseyPrecisionAgTestModule>
        {
            private DbConnection _hostDb;
            private Dictionary<int, DbConnection> _tenantDbs; //only used for db per tenant architecture
            public TestGPASession GPASession { get; private set; }
    
            protected AppTestBase()
            {
                GPASession = Resolve<TestGPASession>();
    
                //Seed initial data for host
                AbpSession.TenantId = null;
                UsingDbContext(context =>
                {
                    context.EntityChangeEventHelper = NullEntityChangeEventHelper.Instance;
                    context.EventBus = NullEventBus.Instance;
    
                    new InitialHostDbBuilder(context).Create();
                    new DefaultTenantBuilder(context).Create();
                });
    
                //Seed initial data for default tenant
                AbpSession.TenantId = 1;
                UsingDbContext(context =>
                {
                    context.EntityChangeEventHelper = NullEntityChangeEventHelper.Instance;
                    context.EventBus = NullEventBus.Instance;
    
                    new TenantRoleAndUserBuilder(context, 1).Create();
                    new TestDataBuilder(context, 1).Create();
                });
    
                LoginAsDefaultTenantAdmin();
            }
    
            protected override void PreInitialize()
            {
               LocalIocManager.Register<IAbpSession, TestGPASession>();
    
                base.PreInitialize();
    
                UseSingleDatabase();
                //UseDatabasePerTenant();
            }
    

    Now, I am facing an issue with dependency injection, in RoleAppService when I access GPASession object, it always resolved as GPASession not with TestGPASession, though I have registered in PreInitilize method as LocalIocManager.Register<IAbpSession, TestGPASession>();. Can you please tell me what I am missing here?

    Thanks

  • 0
    pradippatil created

    Hi,

    Can you please help me on above issue (using custom session in unit testing)?

    Thanks

  • 0
    ismcagdas created
    Support Team

    Hi,

    Can you try to do this in your test module's initialize method.

    Configuration.ReplaceService<IAbpSession, TestGPASession>();
    

    you also need to add "using Abp.Configuration.Startup;".

  • 0
    pradippatil created

    Hi,

    Finally, I got rid of this issue of using custom session properties in unit testing.

    However, I tried the below code as suggested:

    Configuration.ReplaceService<IAbpSession, TestGPASession>();
    

    But, didn't work.

    So, I tried to use interface IGPASession instead of GPASession concrete class as property type in App Service Base class and registered it in AppTestBase's PreInitilize method and It worked!! Below is working code snippet:

    public abstract class GodseyPrecisionAgAppServiceBase : ApplicationService
        {
            public TenantManager TenantManager { get; set; }
    
            public UserManager UserManager { get; set; }
    
            //public GPASession GPASession { get; set; }
            public IGPASession GPASession { get; set; }
    
    public abstract class AppTestBase : AbpIntegratedTestBase<GodseyPrecisionAgTestModule>
        {
            private DbConnection _hostDb;
            private Dictionary<int, DbConnection> _tenantDbs; //only used for db per tenant architecture
            public TestGPASession GPASession { get; private set; }
    
            protected AppTestBase()
            {
                GPASession = Resolve<TestGPASession>();
    
    protected override void PreInitialize()
            {
                LocalIocManager.Register<IGPASession, TestGPASession>();
    
                base.PreInitialize();
    
                UseSingleDatabase();
                //UseDatabasePerTenant();
            }
    

    Thanks for the help!

  • 0
    ismcagdas created
    Support Team

    Hi @pradippatil,

    I remember you have solved this problem but I couldn't find your answer in this topic. Please let us know if you still have this problem.

    Thanks.

  • 1
    kansoftware created

    Hi ,

    How this can be achieved in current version.

    Regards, Harshit