如何在JWT令牌中包含用户登录时间与IP地址信息
问题核心误区先点明
首先你踩的第一个坑是:Client Credentials 授权流本身是无用户上下文的服务间认证流,全程没有用户登录交互环节,既不会返回id_token(这个是用户登录场景才会签发的凭证),也不存在「用户登录时间」「用户登录IP」这类用户会话属性,你之前的方案方向从根上就错了。
另外你尝试的两种方案本身的适用场景也不对:
- 调用
extensionProperties创建的扩展属性,是用来给Azure AD目录对象(比如用户、组)存储静态长期属性的(比如员工工号、内部租户ID这类不会频繁变动的值),而登录IP、登录时间是每次会话都会变的动态值,不可能靠给User对象加字段来自动填充。 - 直接修改应用Manifest配置可选声明,只能映射Azure AD内置的已有属性,没法自动拉取动态的请求IP这类会话数据,而且很多可选声明仅在有用户上下文的授权流(授权码、隐式流等)下才会生效,对Client Credentials流无效。
分场景的正确实现方式
场景1:你确实需要用Client Credentials流(纯服务调用场景)
这个场景下的token是代表应用本身的身份,没有用户维度的信息:
- 如果你要的「signed-in time」是指令牌本身的签发时间,不需要做任何额外配置:默认JWT里就自带
iat标准声明,值是令牌签发的Unix时间戳,直接解析读取即可。 - 如果你需要在token里携带调用方IP这类自定义动态值,唯一的可行方案是配置自定义声明提供程序:给Azure AD配置令牌颁发事件触发器,在令牌生成前调用你自己部署的API,由你的API获取当前令牌请求的来源IP、补充你需要的自定义字段值返回给Azure AD,Azure AD会把这些值注入到最终签发的JWT里。
不要尝试每次请求token前先调用Graph更新用户扩展属性里的IP值,这个方案不仅延迟极高,还会碰到目录接口限流、数据一致性问题,完全不适合生产环境用。
场景2:你实际是要做用户登录场景(选错了授权流)
如果你是有用户参与登录的场景,不需要创建任何扩展属性:
- 登录时间:默认签发的
id_token和access_token里已经自带auth_time声明,值就是用户完成身份验证的Unix时间戳,直接读取即可。 - 登录IP:Azure AD出于安全考虑,默认不会把用户登录IP直接注入到token中,你可以选两种方案实现:
- 同样配置自定义声明提供程序,在用户登录的令牌颁发环节,从登录事件上下文里提取客户端IP,注入到token声明中。
- 不把IP放到token里,在用户登录完成后,通过Graph API查询Azure AD的登录审计日志,根据用户ID和登录时间匹配拿到对应登录IP,存在你自己的业务会话存储中即可。
你之前配置不生效的常见原因
- Client Credentials流不会返回
id_token:只有请求了openid作用域的用户登录场景才会返回id_token,你用客户端凭据流申请.default作用域时根本拿不到这个凭证。 - Manifest里配置的可选声明没有匹配对应的流生效范围:很多用户相关的可选声明不会在纯应用身份的token中返回。
- Azure AD内置可选声明列表里根本没有客户端IP这个选项,你就算手动改Manifest加不存在的声明名,也不会出现在最终的token里。
内容的提问来源于stack exchange,提问作者Ben3119
相关产品推荐
相关产品推荐

