Activities of "maliming"

Hi,

There's no built-in Managed Identity option in the Azure blob provider yet — the config only takes a connection string. But you can plug in DefaultAzureCredential by overriding AzureBlobProvider, since GetBlobContainerClient is protected virtual. We may add native support for this in a future release.

Here's a working override (I verified it builds against Volo.Abp.BlobStoring.Azure 10.2.0 + Azure.Identity):

using System;
using Azure.Identity;
using Azure.Storage.Blobs;
using Volo.Abp.BlobStoring;
using Volo.Abp.BlobStoring.Azure;
using Volo.Abp.DependencyInjection;

namespace MyCompanyName.MyProjectName;

[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(IBlobProvider), typeof(AzureBlobProvider))]
public class MyAzureBlobProvider : AzureBlobProvider
{
    public MyAzureBlobProvider(
        IAzureBlobNameCalculator azureBlobNameCalculator,
        IBlobNormalizeNamingService blobNormalizeNamingService)
        : base(azureBlobNameCalculator, blobNormalizeNamingService)
    {
    }

    protected override BlobContainerClient GetBlobContainerClient(BlobProviderArgs args)
    {
        var configuration = args.Configuration.GetAzureConfiguration();

        // Reuse the existing ConnectionString slot to carry the storage account URL,
        // e.g. "https://<account-name>.blob.core.windows.net".
        var serviceUri = new Uri(configuration.ConnectionString);
        var credential = new DefaultAzureCredential();

        var blobServiceClient = new BlobServiceClient(serviceUri, credential);

        return blobServiceClient.GetBlobContainerClient(GetContainerName(args));
    }
}

In your container configuration just put the storage account URL where the connection string used to go:

Configure<AbpBlobStoringOptions>(options =>
{
    options.Containers.ConfigureDefault(container =>
    {
        container.UseAzure(azure =>
        {
            azure.ConnectionString = "https://<your-account>.blob.core.windows.net";
            azure.ContainerName = "my-container";
            azure.CreateContainerIfNotExists = true;
        });
    });
});

Make sure the App Service's System-Assigned Managed Identity is granted the Storage Blob Data Contributor role on the storage account — that's what DefaultAzureCredential will use at runtime. If you want to be explicit you can swap new DefaultAzureCredential() for new ManagedIdentityCredential().

If you still see errors after this, set AZURE_LOG_LEVEL=verbose on the App Service to capture Azure.Identity diagnostic output and share the exception + relevant log snippet — we can take another look from there.

Thanks

Hi,

Reproduced locally on 10.4 and got it down to two things:

  1. The earlier ChangePassword → Login bounce. Abp.Account.Cookie is a short-lived purpose cookie that doesn't carry a security stamp, but the scheme had SecurityStampValidator wired on it. After SecurityStampValidatorOptions.ValidationInterval elapses the validation always fails, the ticket is rejected, and the user is redirected back to Login. Default interval is 30 minutes, which is why it's intermittent. Fixed by removing the validator and disabling sliding expiration on this cookie.

  2. Force change password not working from a tenant. In Shared User Accounts, IsActive / LockoutEnabled / ShouldChangePasswordOnNextLogin are host-only policy fields — the backend silently restores them when the request comes from a tenant context. The MVC / Blazor / Angular edit forms weren't reflecting that, so the checkbox looked editable and you could "save" it without any effect. Fixed by disabling those inputs in the tenant context so the UI matches the backend.

That said, you can only force-change-password a user that exists at the host level — i.e. has a host-scoped user record (either a host user with TenantId = null, or a self-registered user with TenantId = Guid.Empty that was later invited into the tenant). Users invited directly into a tenant may have tenant-scoped/shadow records, but they don't have a host-scoped user record that the host admin can manage for this policy. If you need this flow to work for tenant-invited users, the workflow is to invite them on the host side first. Supporting force-change-password for tenant-only users would be a separate product decision, not part of this fix.

Both fixes ship in the next patch.

Thanks

Great 👍

Thanks. I will check it asap.

Hi,

Thanks for the details. I tried the exact same setup on my side (10.3.0 source, separate tenant database, host shadow with a different Id from the tenant user) and Force change password on the invited tenant user still goes through fine — so something else in your environment is different from a fresh template setup.

A minimal reproduction project would really help. Either invite https://github.com/maliming to a private GitHub repo, or zip and send via wetransfer to liming.ma@volosoft.com.

Thanks

Hi,

I tried to reproduce this on the same setup (Shared user accounts + tiered + separate tenant database) and Force change password on a tenant user works fine for me — so we're missing some specifics from your environment.

Could you walk me through the exact steps to reproduce, starting from a fresh abp new project, plus a couple of details:

  1. Exact ABP version (10.3.0 / 10.3.1 / ...)
  2. Does the tenant use its own connection string (Saas → Tenants → Connection Strings) or share the host DB?
  3. How was the tenant user created — invited, created by host admin via "Use as tenant", or seeded directly?
  4. Does test.password exist in the host DB only, the tenant DB only, or both? If both, are the Ids the same?

If easier, a minimal reproduction project would be the fastest path. Either invite https://github.com/maliming to a private GitHub repo, or zip and send via wetransfer to liming.ma@volosoft.com.

Thanks

Hi,

Sorry, my snippet used the wrong overload. Could you try this instead:

context.Services.PostConfigure<CookieAuthenticationOptions>(
    AccountPageModel.AccountCookieSchemeName,
    options =>
    {
        options.Events.OnValidatePrincipal = ctx => Task.CompletedTask;
    });

Thanks

Hi,

Thanks for the version info. With ABP 10.1.1 + Microservice + Angular all the pieces should be in place by default — every *.HttpApi.Host in the microservice template ships with IsDynamicClaimsEnabled = true, and the Angular client calls /connect/revocat and /connect/endsession from inside angular-oauth2-oidc (in oAuthService.revokeTokenAndLogout()), so you won't see those calls in your own code. Both endpoints are wired on the server to revoke the IdentitySession.

Since the behavior on your side doesn't match that, could you share two things so we can see exactly what's happening:

  1. HAR file of the full logout flow — capture the network traffic from clicking logout until you land back on the login page. How to capture a HAR: https://abp.io/support/questions/8622/How-to-enable-Debug-logs-for-troubleshoot-problems#answer-3a1f7c9e-eb0b-eb9c-3535-1beae8e8ba43 — we need to see whether /connect/revocat and /connect/endsession are actually called and with what status.

  2. AuthServer Debug logs during the same logout. Set the global log level to Debug (rather than only a couple of categories) so we have full context to keep investigating if needed. How to enable Debug logs: https://abp.io/support/questions/8622/How-to-enable-Debug-logs-for-troubleshoot-problems

Also, one short note on how you're testing — are you doing it inside the Angular app (UI-driven logout, then making a call from the app), or are you copying the access token out and replaying it with Postman / curl?

The HAR and logs can be too big for the thread, please email them to liming.ma@volosoft.com and reference this question.

Thanks

Hi,

For Problem 1 (the empty Settings page): under Shared user accounts the identity- and account-related settings (password policy, lockout, external logins, two-factor, etc.) are global to the whole system and managed only on the host side so every tenant shares a consistent policy. That's why the Identity and Account setting groups are hidden from tenants by their contributors. The remaining groups in the page are host-only and get filtered out by the permission check for a tenant admin — that leaves the page blank. We've opened a PR to render a small empty state instead: https://github.com/abpframework/abp/pull/25541. It ships in the next release.

For Problem 2 (Force change password loops back to Login): the Abp.Account.Cookie purpose cookie is configured with SecurityStampValidator.ValidatePrincipalAsync as OnValidatePrincipal, but the cookie is written without a SecurityStamp claim. So once SecurityStampValidatorOptions.ValidationInterval elapses, the stamp comparison fails, the cookie is rejected, and ChangePassword signs the user out and redirects back to Login. By default the interval is 30 minutes, so a fresh cookie skips the check and the bug stays hidden — your environment seems to trigger it.

You can drop the broken handler in your Web module's ConfigureServices until the next release:

PostConfigure<CookieAuthenticationOptions>(AccountPageModel.AccountCookieSchemeName, options =>
{
    options.Events.OnValidatePrincipal = ctx => Task.CompletedTask;
});

The purpose cookie is protected by its 10-minute ExpireTimeSpan and the purpose claim, so dropping the stamp validation doesn't reduce security. We'll fix this in the next ABP version, and your ticket has been refunded.

Thanks

Hi,

Your direction is correct — call IIdentityUserIntegrationService from your WorkItem service and fill the username on the DTO. Since you're on a Business license and your IdentityService uses the Pro packages, go with Volo.Abp.Identity.Pro.HttpApi.Client (not the open-source one) so the contracts stay consistent across services.

About why Suite doesn't list IdentityUser in that dropdown: in the microservice template, Identity runs as its own service with its own database, and your WorkItem service's Domain project does not (and should not) reference Volo.Abp.Identity.Pro.Domain. Suite hides it on purpose — cross-database EF navigation isn't possible here. Keep AssignedUserId as a plain Guid / Guid? and resolve the username at the application layer.

The username data lives in the IdentityService database. ABP already exposes a built-in integration endpoint for this (/integration-api/identity/users/search/by-ids) — you don't need to write anything on the Identity side, just consume it from your WorkItem service.

Three steps:

  1. Add the package to your WorkItem service .csproj:
<PackageReference Include="Volo.Abp.Identity.Pro.HttpApi.Client" Version="$(YourAbpVersion)" />
  1. Add the module dependency in your WorkItem service module class. This is what registers the IIdentityUserIntegrationService client proxy in DI — without it the interface can't be resolved:
using Volo.Abp.Identity;

[DependsOn(
    // ...your existing dependencies
    typeof(AbpIdentityHttpApiClientModule)
)]
public class WorkItemServiceModule : AbpModule
{
}
  1. Inject the integration service in your WorkItemsAppService and enrich the DTOs after the list query. Use SearchByIdsAsync so it's one remote call per page, not N+1:
private readonly IIdentityUserIntegrationService _identityUserIntegrationService;

public WorkItemsAppService(
    /* ...existing deps */,
    IIdentityUserIntegrationService identityUserIntegrationService)
{
    _identityUserIntegrationService = identityUserIntegrationService;
}

private async Task FillAssignedUserNamesAsync(IReadOnlyList<WorkItemDto> items)
{
    var userIds = items
        .Where(x => x.AssignedUserId.HasValue)
        .Select(x => x.AssignedUserId!.Value)
        .Distinct()
        .ToArray();

    if (userIds.Length == 0)
    {
        return;
    }

    var users = await _identityUserIntegrationService.SearchByIdsAsync(userIds);
    var userMap = users.Items.ToDictionary(u => u.Id, u => u.UserName);

    foreach (var item in items)
    {
        if (item.AssignedUserId.HasValue &&
            userMap.TryGetValue(item.AssignedUserId.Value, out var userName))
        {
            item.AssignedUserName = userName;
        }
    }
}

Then call FillAssignedUserNamesAsync(result.Items) at the end of your list method (right before returning), and add an AssignedUserName property to WorkItemDto.

A few notes:

  • The Suite-scaffolded appsettings.json already has RemoteServices:AbpIdentity:BaseUrl pointing to your IdentityService, so no extra configuration is needed.
  • Token forwarding to the Identity service is set up by the microservice template out of the box.
  • UserData also carries Name, Surname, Email, IsActive etc., so you can map other fields the same way if you need them later.

If anything doesn't work or you run into any other issues, feel free to let me know.

Thanks

Showing 401 to 410 of 12915 entries
Boost Your Development
ABP Live Training
Packages
See Trainings
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
Made with ❤️ on ABP v10.8.0-preview. Updated on November 02, 2026, 06:56
1
ABP Assistant
🔐 You need to be logged in to use the chatbot. Please log in first.