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

如何基于.NET和GraphAPI实现Entra ID用户临时密码变更的事件式检测

问题

我正在构建一个集成Microsoft Entra ID的用户管理系统。在本系统创建用户时,会同步在Entra ID中预配用户,并向其发送包含临时密码的欢迎邮件。

我需要追踪用户是否已修改临时密码——以此标记用户为“已激活”。当前定义“已激活”用户为无需在下次登录时修改密码的用户。

目前使用Microsoft Graph获取状态,现有简化逻辑如下:

public async Task<List<string>> GetUserIdsByActivationStatusAsync(
    bool isActivated,
    CancellationToken cancellationToken
)
{
    var userIds = new List<string>();

    // 获取用户列表(简化处理,最多999条)
    var usersPage = await _graphClient.Users.GetAsync(
        config =>
        {
            config.QueryParameters.Select = ["id"];
            config.QueryParameters.Top = 999;
        },
        cancellationToken
    );

    var users = usersPage?.Value ?? [];

    foreach (var user in users)
    {
        if (string.IsNullOrEmpty(user.Id))
            continue;

        var userWithProfile = await _graphClient.Users[user.Id].GetAsync(
            config =>
            {
                config.QueryParameters.Select = ["passwordProfile"];
            },
            cancellationToken
        );

        bool userIsActivated =
            !userWithProfile?.PasswordProfile?.ForceChangePasswordNextSignIn ?? true;

        if (userIsActivated == isActivated)
        {
            userIds.Add(user.Id);
        }
    }

    return userIds;
}

现有逻辑的假设:

  • 若ForceChangePasswordNextSignIn为true → 用户尚未登录 → 未激活
  • 若为false或PasswordProfile整体为null → 假设用户已登录 → 已激活

该逻辑可正常运行,但存在以下问题:

  • 效率低下(需遍历每个用户)
  • 被动式检测——仅在查询时才能知晓用户激活状态
  • 无法支持数千级用户的扩展

需要解决的问题:
是否存在无需遍历用户的事件驱动方式,可检测Entra ID中用户修改临时密码(变为“已激活”)的操作?

已知Entra ID的自定义身份验证扩展-TokenIssuanceStart(颁发令牌前触发的事件)功能,是否有其他基于Entra ID的方式可追踪“带临时密码的新用户”→“已修改密码并登录的用户”的状态转换?或Entra ID能否通过HTTP端点主动通知用户登录并修改密码的事件?


可行的事件驱动与优化方案

1. 审计日志+Webhook实时通知

Entra ID会记录用户首次登录修改临时密码的审计事件,可通过Azure Monitor配置警报规则,将目标事件推送到你的系统端点:

  • 筛选条件:Category为UserManagement,ActivityDisplayName为Update user password (self-service)(对应用户自行修改临时密码的操作)
  • 配置方式:在Azure门户的Entra ID审计日志模块创建警报规则,设置动作组为Webhook,指定你的系统接收地址
  • 优势:实时触发,无需主动轮询,天然支持大规模用户场景

2. 优化Microsoft Graph批量查询(非事件驱动但大幅提效)

如果暂时无法切换到事件驱动,可直接通过Graph的OData筛选器批量获取目标用户,避免逐个查询:

public async Task<List<string>> GetUserIdsByActivationStatusAsync(
    bool isActivated,
    CancellationToken cancellationToken
)
{
    var filter = isActivated 
        ? "passwordProfile/forceChangePasswordNextSignIn eq false or passwordProfile eq null" 
        : "passwordProfile/forceChangePasswordNextSignIn eq true";

    var usersPage = await _graphClient.Users.GetAsync(
        config =>
        {
            config.QueryParameters.Select = ["id"];
            config.QueryParameters.Filter = filter;
            config.QueryParameters.Top = 999;
        },
        cancellationToken
    );

    var userIds = usersPage?.Value?.Where(u => !string.IsNullOrEmpty(u.Id)).Select(u => u.Id).ToList() ?? [];

    // 处理分页逻辑,支持超过999条用户的场景
    while (!string.IsNullOrEmpty(usersPage?.OdataNextLink))
    {
        usersPage = await _graphClient.Users.WithUrl(usersPage.OdataNextLink).GetAsync(cancellationToken: cancellationToken);
        userIds.AddRange(usersPage?.Value?.Where(u => !string.IsNullOrEmpty(u.Id)).Select(u => u.Id) ?? []);
    }

    return userIds;
}
  • 优势:单次批量筛选,无需遍历每个用户;支持分页获取全部结果,效率比原逻辑提升数倍

3. TokenIssuanceStart身份验证扩展

利用你提到的TokenIssuanceStart事件,在用户每次获取令牌前触发自定义逻辑:

  • 检查用户的forceChangePasswordNextSignIn状态,若从true变为false,则调用你的系统API标记用户为已激活
  • 注意:需添加状态判断逻辑,避免重复触发标记操作

4. Microsoft Graph订阅用户更新事件

通过Graph的订阅功能,精准追踪用户passwordProfile字段的变更:

  • 订阅users资源的updated事件,指定筛选条件为passwordProfile/forceChangePasswordNextSignIn字段变更
  • 当该字段从true变为false时,Entra ID会向你的Webhook端点发送通知
  • 优势:仅在目标状态转换时触发,无冗余通知

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 19:19:58