Open Closed

CurrentUser and Tenant About #8311


User avatar
0
Teknosol created
  • ABP Framework version: v7.1.1
  • Database System: EF Core ( PostgreSQL, etc..)
  • Tiered (for MVC) or Auth Server Separated (for Angular): yes/no

Hi, I am sending data and jwt from producer service to consumer with masstransit. When recording the data, I want it to record by taking the userid and tenantid from jwt, but it does not work. I request your support.

Note: If I do not add the tenant id to this ClaimsPrincipal class, only the userid is added to the creatorid database. When I add both, it does not work.

Below are the producer and consumer methods I use:

Producer:

 [HttpPost]
 [Route("create-screen-design")]
 public async Task<IActionResult> StartProducer(ScreenDesignCreateCommand command)
 {
     string authHeader = _httpContextAccessor.HttpContext.Request.Headers["Authorization"];
     var jwtHeader = authHeader.Replace("Bearer ", string.Empty);

     var response1 = await _requestClient.GetResponse<Result<ScreenDesignCreateResult>>(command, x => x.UseExecute(context => context.Headers.Set("jwt", jwtHeader)), timeout: TimeSpan.FromSeconds(30));


     if (!response1.Message.IsSuccess)
         return BadRequest(response1.Message);
     return Ok(response1.Message);

 }

Consumer:

 public class CreateScreenDesignConsumer : IConsumer<IScreenDesignCreateCommand>, ITransientDependency
 {
     private readonly IScreenRootManager _screenRootManager;
     private readonly ILogger<CreateScreenDesignConsumer> _logger;
     private readonly ICurrentPrincipalAccessor _currentPrincipalAccessor;

     public CreateScreenDesignConsumer(IScreenRootManager screenRootManager, ILogger<CreateScreenDesignConsumer> logger, ICurrentPrincipalAccessor currentPrincipalAccessor)
     {
         _screenRootManager = screenRootManager;
         _logger = logger;
         _currentPrincipalAccessor = currentPrincipalAccessor;
     }

     public virtual async Task Consume(ConsumeContext<IScreenDesignCreateCommand> context)
     {
         var jwtHeader = context.Headers.Get<string>("jwt");
         var handler = new JwtSecurityTokenHandler();
         var jsonToken = handler.ReadToken(jwtHeader) as JwtSecurityToken;
         var userId = jsonToken.Payload.Sub;
         var tenantId = jsonToken.Payload["tenantid"].ToString();


         var newPrincipal = new ClaimsPrincipal(
        new ClaimsIdentity(
            new Claim[]
            {
                 new Claim(AbpClaimTypes.UserId, userId),
                 new Claim(AbpClaimTypes.TenantId, tenantId)
            }
        )
    );

         using (_currentPrincipalAccessor.Change(newPrincipal))
         {
             try
             {

                 var result = await _screenRootManager.CreateAsync(context.Message);
                 await context.RespondAsync(new Result<ScreenDesignCreateResult>(data: result));

             }
             catch (Exception ex)
             {
                 await context.RespondAsync<Fault<Result>>
               (new { Message = "ScreenDeisgn:CreateFail", FaultMessage = ex.Message, FaultStackTrace = ex.StackTrace });

             }
         }


     }
 }


16 Answer(s)
  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    Hi,

    What is the tenantId and userId value?

  • User Avatar
    0
    Teknosol created

    Hi,

    Two of the values ​​are strings

    Userid = "3a165633-f48a-b83d-9a63-c829ed20485e" tenantid = "3a165633-f271-2c25-5419-f28719001528"

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    you can try

    using(CurrentTenant.Change(tenantId))
    using(_currentPrincipalAccessor.Change(claims...)
    {
        // check if current user is available here
        var userId =  CurrentUser.Id;
        
    }
    
  • User Avatar
    0
    Teknosol created

    This class is a consumer class, not a domain service or application. I get Currenttenant or CurrentUser with dependency injection. I can't use it with the CurrentTenant global variable.

    In the scenario of the code below, although two IDs are filled, it only writes the creatorId to the database.

    If you want to check the project, I'm adding the link. https://we.tl/t-RkLhH4N3mA

     public class CreateScreenDesignConsumer : IConsumer<IScreenDesignCreateCommand>, ITransientDependency
    {
        private readonly IScreenRootManager _screenRootManager;
        private readonly ILogger<CreateScreenDesignConsumer> _logger;
        private readonly ICurrentPrincipalAccessor _currentPrincipalAccessor;
        private readonly ICurrentTenant _currentTenant;
        private readonly ICurrentUser _currentUser;
    
        public CreateScreenDesignConsumer(IScreenRootManager screenRootManager, ILogger<CreateScreenDesignConsumer> logger, ICurrentPrincipalAccessor currentPrincipalAccessor, ICurrentTenant currentTenant, ICurrentUser currentUser)
        {
            _screenRootManager = screenRootManager;
            _logger = logger;
            _currentPrincipalAccessor = currentPrincipalAccessor;
            _currentTenant = currentTenant;
            _currentUser = currentUser;
        }
    
        public virtual async Task Consume(ConsumeContext<IScreenDesignCreateCommand> context)
        {
            var jwtHeader = context.Headers.Get<string>("jwt");
            var handler = new JwtSecurityTokenHandler();
            var jsonToken = handler.ReadToken(jwtHeader) as JwtSecurityToken;
            var userId = jsonToken.Payload.Sub;
            var tenantId = jsonToken.Payload["tenantid"].ToString();
    
    
            var newPrincipal = new ClaimsPrincipal(
           new ClaimsIdentity(
               new Claim[]
               {
                    new Claim(AbpClaimTypes.UserId, userId),
                   // new Claim(AbpClaimTypes.TenantId, tenantId)
               }
           )
       );
            using (_currentTenant.Change(Guid.Parse(tenantId)));
            using (_currentPrincipalAccessor.Change(newPrincipal))
            {
              //tmptenantid value is null
                var tmptenantid = _currentTenant.Id;
                var tmpuserid = _currentUser.Id;
                try
                {
    
                    var result = await _screenRootManager.CreateAsync(context.Message);
                    await context.RespondAsync(new Result<ScreenDesignCreateResult>(data: result));
    
                }
                catch (Exception ex)
                {
                    await context.RespondAsync<Fault<Result>>
                  (new { Message = "ScreenDeisgn:CreateFail", FaultMessage = ex.Message, FaultStackTrace = ex.StackTrace });
    
                }
            }
    
    
        }
    }
    

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    Because there is no saas module, ABP can't get the tenant data from TenantStore

    See:

    https://abp.io/docs/latest/framework/architecture/multi-tenancy#configuration-data-store

    if you don't want to depend on saas module, you can try override the DefaultTenantStore

    [Dependency(ReplaceServices = true)]
    [ExposeServices(typeof(ITenantStore))]
    public class MyTenantStore : ITenantStore, ITransientDependency
    {
        .....
    
        public Task<TenantConfiguration> FindAsync(Guid id)
        {
            return Task.FromResult(new TenantConfiguration(){
                Id = id,
                Name = "...."
            });
        }
    }
    
  • User Avatar
    0
    Teknosol created

    Thank you for your answer, but we have existing saas, identity, administration services. APIs in our other projects can send requests here and perform tenant and auth authentications in these services. We want to make this screen design service work the same way. What settings do we need to make?

    In the example you sent, it changes the existing tenant system, this is not suitable for us.

    This image is a screenshot of our saas project, currently working:

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    APIs in our other projects can send requests here and perform tenant and auth authentications in these services. We want to make this screen design service work the same way. What settings do we need to make?

    you should add the AbpAspNetCoreMvcClientModule module dependency. and config remote service

  • User Avatar
    0
    Teknosol created

    Hi,

    I did what you said as in the screenshot below, tenantid still comes up empty. I am sharing the project including what I did. I kindly request your support.

    https://we.tl/t-xVUJXhrefd

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    Hi,

    How do I test it? could give me a valid access_token and tenantid.

  • User Avatar
    0
    Teknosol created

    I will send you jwt by e-mail

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    okay

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    HI,

    remove ;

    and it works

  • User Avatar
    0
    Teknosol created

    I deleted the comma but this time it does not write the CreatorId in the db.

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    Add new Claim(AbpClaimTypes.TenantId, tenantId)

  • User Avatar
    0
    Teknosol created

    The problem is solved, we were able to register both IDs, thank you. When we add the authorize attribute to the method as in the picture, it enters the method, but we want to check the authorization, how can we do it?

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    Since the problem was resolved, i close this.

    but we want to check the authorization, how can we do it?

    You need to manually call the API to check it.

Made with ❤️ on ABP v9.1.0-preview. Updated on December 13, 2024, 06:09