You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为Elsa v3配置Azure AD身份验证?

Elsa v3 配置Azure AD身份验证方案解析与修正

当前方案的问题分析

你当前的代码存在两个核心问题:

  1. 存储注册错误:AddUserStore<User>()和AddRoleStore<Role>()用法不符合Microsoft Identity规范——这两个方法的泛型参数需要传入实现了对应接口的存储类型,而非User/Role实体类。Azure AD作为外部身份提供者,并不直接提供IUserStore<User>或IRoleStore<Role>的本地实现,因此这两行代码会导致DI容器无法找到对应服务,触发报错。
  2. 接口适配逻辑偏差:Elsa的IUserStore/IRoleStore是自定义抽象,与Microsoft Identity的同名泛型接口完全独立。你试图注入Microsoft Identity的存储接口,但Azure AD场景下无需本地存储,应通过Graph API获取用户/角色数据。

当前方案修正步骤

1. 移除错误的存储注册代码

将UseAzureIdentityProvider方法中的错误注册代码删除,替换为Microsoft Graph服务注册(用于获取Azure AD用户/角色数据):

public static class ElsaAzureActiveDirectoryIdentityAdapterServiceCollectionExtensions
{
    public static void UseAzureIdentityProvider(this IdentityFeature identity, IConfiguration configuration)
    {
        // 注册Microsoft Graph服务(用于访问Azure AD数据)
        var tenantId = configuration["AzureAd:TenantId"];
        var clientId = configuration["AzureAd:ClientId"];
        var clientSecret = configuration["AzureAd:ClientSecret"];
        
        identity.Services.AddMicrosoftGraph(options =>
        {
            options.Scopes = "User.Read Directory.Read.All";
        }).AddAuthenticationProvider(new ClientCredentialProvider(
            new ClientCredential(clientId, clientSecret),
            $"https://login.microsoftonline.com/{tenantId}/v2.0"));

        // 注册适配器
        identity.Services.AddSingleton<ElsaAzureActiveDirectoryIdentityAdapter>();
        identity.Services.AddSingleton<IRoleStore>(provider => provider.GetRequiredService<ElsaAzureActiveDirectoryIdentityAdapter>());
        identity.Services.AddSingleton<IUserStore>(provider => provider.GetRequiredService<ElsaAzureActiveDirectoryIdentityAdapter>());

        identity.UserStore = provider => provider.GetRequiredService<IUserStore>();
        identity.RoleStore = provider => provider.GetRequiredService<IRoleStore>();
    }
}

2. 修改适配器类,通过Graph API获取数据

调整适配器,注入GraphServiceClient而非Microsoft Identity的存储接口,直接从Azure AD获取用户/角色:

public class ElsaAzureActiveDirectoryIdentityAdapter(GraphServiceClient graphClient)
    : IRoleStore, IUserStore
{
    #region Role Store Methods
    public Task AddAsync(Role role, CancellationToken cancellationToken = default) 
        => throw new NotImplementedException("Azure AD角色需在门户管理,不支持本地添加");

    public Task DeleteAsync(RoleFilter filter, CancellationToken cancellationToken = default) 
        => throw new NotImplementedException("Azure AD角色需在门户管理,不支持本地删除");

    public Task SaveAsync(Role role, CancellationToken cancellationToken = default) 
        => throw new NotImplementedException("Azure AD角色需在门户管理,不支持本地修改");

    public async Task<Role?> FindAsync(RoleFilter filter, CancellationToken cancellationToken = default)
    {
        if (filter.Id != null)
        {
            var azureRole = await graphClient.DirectoryRoles[filter.Id].Request().GetAsync(cancellationToken);
            return new Role { Id = azureRole.Id, Name = azureRole.DisplayName };
        }
        return null;
    }

    public async Task<IEnumerable<Role>> FindManyAsync(RoleFilter filter, CancellationToken cancellationToken = default)
    {
        var roles = await graphClient.DirectoryRoles.Request().GetAsync(cancellationToken);
        return roles.Select(r => new Role { Id = r.Id, Name = r.DisplayName });
    }
    #endregion

    #region User Store Methods
    public Task SaveAsync(User user, CancellationToken cancellationToken = default) 
        => throw new NotImplementedException("Azure AD用户需在门户管理,不支持本地修改");

    public Task DeleteAsync(UserFilter filter, CancellationToken cancellationToken = default) 
        => throw new NotImplementedException("Azure AD用户需在门户管理,不支持本地删除");

    public async Task<User?> FindAsync(UserFilter filter, CancellationToken cancellationToken = default)
    {
        if (filter.Id != null)
        {
            var azureUser = await graphClient.Users[filter.Id].Request().GetAsync(cancellationToken);
            return MapToElsaUser(azureUser);
        }

        if (filter.Name != null)
        {
            var users = await graphClient.Users.Request()
                .Filter($"userPrincipalName eq '{filter.Name}'")
                .GetAsync(cancellationToken);
            return users.FirstOrDefault()?.MapToElsaUser();
        }

        return null;
    }

    private User MapToElsaUser(Microsoft.Graph.Models.User azureUser)
    {
        return new User
        {
            Id = azureUser.Id,
            Name = azureUser.UserPrincipalName,
            Email = azureUser.Mail ?? azureUser.UserPrincipalName
        };
    }
    #endregion
}

Elsa Studio v3(Blazor WASM)配置Azure AD的标准方法

如果无需自定义用户存储,仅需实现Azure AD认证,可采用以下更简单的方案:

1. 后端API配置(ASP.NET Core)

// 注册Azure AD JWT认证
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));

// 配置Elsa使用JWT认证
builder.Services.AddElsa(elsa =>
{
    elsa.UseIdentity(identity =>
    {
        identity.TokenOptions = options =>
        {
            options.ValidIssuer = builder.Configuration["AzureAd:Issuer"];
            options.ValidAudience = builder.Configuration["AzureAd:Audience"];
        };
        identity.UseJwtAuthentication();
    });
});

2. Blazor WASM客户端配置

// 注册MSAL认证
builder.Services.AddMsalAuthentication(options =>
{
    builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);
    options.ProviderOptions.DefaultAccessTokenScopes.Add("api://your-backend-api-client-id/access_as_user");
});

3. 配置文件(appsettings.json)

{
  "AzureAd": {
    "Authority": "https://login.microsoftonline.com/your-tenant-id",
    "ClientId": "your-client-id",
    "Audience": "api://your-backend-api-client-id",
    "ValidateAuthority": true
  }
}

内容的提问来源于stack exchange,提问作者Adam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 11:22:06