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

如何在C#应用中通过API为Keycloak的access_token设置自定义Claim

解决Keycloak生成带自定义Claim的Access Token问题

需求背景

同一用户需根据应用状态访问不同资源,需在C#应用中生成带自定义Claim的Keycloak Access Token,排除创建多用户、Cookie存储、URL传参的实现方案。尝试使用uma-ticket方式时出现错误:

{
"error": "invalid_grant",
"error_description": "Invalid bearer token"
}

可行实现方案

方案1:基于资源所有者密码凭证流扩展自定义Claim

  1. Keycloak后台配置自定义Claim映射

    • 进入目标Realm的客户端页面,选择你的应用客户端,切换到Mappers标签
    • 点击Create,选择Script Mapper类型
    • 填写名称后,在Script中编写逻辑,根据请求传入的自定义参数生成Claim,示例脚本:
      var customParam = session.getContext().getRequestParameters().getFirst("app_state");
      if (customParam) {
        token.setOtherClaims("app_state", customParam);
      }
      
    • 保存映射规则,确保Token Claim Name设置为你需要的Claim键名(比如app_state)
  2. C#代码调用Token端点生成带自定义Claim的Token

    using System.Net.Http;
    using System.Collections.Generic;
    using System.Threading.Tasks;
    using Newtonsoft.Json.Linq;
    
    public async Task<string> GetAccessTokenWithCustomClaim(string username, string password, string appState)
    {
        var client = new HttpClient();
        var tokenEndpoint = "http://你的Keycloak地址/auth/realms/你的Realm名/protocol/openid-connect/token";
        var formData = new Dictionary<string, string>
        {
            { "grant_type", "password" },
            { "client_id", "你的应用客户端ID" },
            { "client_secret", "你的应用客户端密钥" }, // 仅保密客户端需要填写
            { "username", username },
            { "password", password },
            { "app_state", appState } // 对应Script Mapper中读取的自定义参数
        };
    
        var response = await client.PostAsync(tokenEndpoint, new FormUrlEncodedContent(formData));
        response.EnsureSuccessStatusCode();
        var responseJson = JObject.Parse(await response.Content.ReadAsStringAsync());
        return responseJson["access_token"].ToString();
    }
    

方案2:基于客户端凭证流+用户模拟生成Token(无需用户密码)

适合后台服务场景,需管理员权限:

  1. Keycloak权限配置

    • 给用于调用接口的客户端添加realm:impersonation角色(在客户端Scope标签页添加对应角色)
  2. C#代码实现

    using System.Net.Http;
    using System.Collections.Generic;
    using System.Threading.Tasks;
    using Newtonsoft.Json.Linq;
    
    public async Task<string> GetImpersonatedTokenWithCustomClaim(string userId, string appState)
    {
        var client = new HttpClient();
        // 1. 获取管理员级别的客户端凭证Token
        var adminTokenEndpoint = "http://你的Keycloak地址/auth/realms/你的Realm名/protocol/openid-connect/token";
        var adminForm = new Dictionary<string, string>
        {
            { "grant_type", "client_credentials" },
            { "client_id", "管理员客户端ID" },
            { "client_secret", "管理员客户端密钥" }
        };
        var adminResponse = await client.PostAsync(adminTokenEndpoint, new FormUrlEncodedContent(adminForm));
        var adminToken = JObject.Parse(await adminResponse.Content.ReadAsStringAsync())["access_token"].ToString();
    
        // 2. 调用用户模拟接口,传入自定义Claim
        var impersonateEndpoint = $"http://你的Keycloak地址/auth/admin/realms/你的Realm名/users/{userId}/impersonation";
        var requestBody = new
        {
            clientId = "你的应用客户端ID",
            additionalClaims = new Dictionary<string, object> { { "app_state", appState } }
        };
        client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", adminToken);
        var impersonateResponse = await client.PostAsJsonAsync(impersonateEndpoint, requestBody);
        impersonateResponse.EnsureSuccessStatusCode();
        var impersonateJson = JObject.Parse(await impersonateResponse.Content.ReadAsStringAsync());
        return impersonateJson["token"].ToString();
    }
    

uma-ticket错误排查方向

出现invalid_grant: Invalid bearer token通常是以下原因:

  • 传入的Bearer Token无效(过期、签名错误、不属于目标Realm/客户端)
  • 未正确配置UMA资源与权限,需先在Keycloak后台创建对应UMA资源,并确保Token拥有访问该资源的权限
  • 请求参数缺失或格式错误,比如未传入resource_id等UMA流必填参数

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 05:50:26