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

RestSharp POST请求获取令牌遇401授权错误排查

解决RestSharp请求获取Token返回401(无效客户端ID/密钥)的问题

问题背景

将Postman中验证通过的API测试转换为RestSharp代码,通过POST请求获取access_token和refreshToken。已确认使用与Postman完全一致的client_id和client_secret,但请求返回401 Unauthorized错误,提示“Invalid client id or secret”。

Postman请求详情

请求体

Postman请求体

请求头

Postman请求头

尝试的代码及错误

初始代码实现

using Newtonsoft.Json.Linq;
using RestSharp;

private (string,string) GetAccessToken_RefreshToken()
{
    var request = new RestRequest(URL_TOKEN, Method.Post);
    request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
    request.AddHeader("Authorization", "Basic dndmci1hcGktY2xpZW50Og==");
    request.AddHeader("Cache-Control", "no-cache");

    // Request Body as x-www-form-urlencoded
    request.AddParameter("grant_type", "password", ParameterType.GetOrPost);
    request.AddParameter("username", "SALESPERSON1", ParameterType.GetOrPost);
    // request.AddParameter("X-IBM-Client-Id:", "6cc43ffd-9818-43d4-b1d5-4d87fa5258de");
    request.AddParameter("client_id", "vwfr-trusted-api-client", ParameterType.GetOrPost);
    request.AddParameter("client_secret", "5876d4ff-6434-40ce-9635-cf3920b240d1", ParameterType.GetOrPost);

    RestResponse response = client.Execute(request);
    Console.WriteLine(response);
    if (response.StatusCode == System.Net.HttpStatusCode.OK)
    {
        JObject jsonObject = JObject.Parse(response.Content);
        accessToken = (string)jsonObject["access_token"];
        refreshToken = (string)jsonObject["refresh_token"];
        Console.WriteLine($"Token: {AccessToken}");
        Console.WriteLine($"Refresh_token: {RefreshToken} " + "\n");
    }
    else
    {
        Console.WriteLine(response.Content);
        Console.WriteLine("Failed to get access token. Status code: " + response.StatusCode);
    }
    return (accessToken, refreshToken);
}

错误响应

RestSharp.RestResponse
{"httpCode":"401","httpMessage":"Unauthorized","moreInformation":"Invalid client id or secret."}

新版代码实现(尝试URL编码参数)

private (string, string) GetAccessToken_RefreshToken()
{
    var request = new RestRequest(URL_TOKEN, Method.Post);
    request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
    request.AddHeader("Authorization", "Basic dndmci1hcGktY2xpZW50Og==");
    request.AddHeader("Cache-Control", "no-cache");

    var parameters = new List<KeyValuePair<string, string>>
    {
        new KeyValuePair<string, string>("grant_type", "password"),
        new KeyValuePair<string, string>("username", "SALESPERSON1"),
        new KeyValuePair<string, string>("client_id", "vwfr-trusted-api-client"),
        new KeyValuePair<string, string>("client_secret", "5876d4ff-6434-40ce-9635-cf3920b240d1")
    };

    foreach (var parameter in parameters)
    {
        var encodedValue = HttpUtility.UrlEncode(parameter.Value);
        request.AddParameter(parameter.Key, encodedValue, ParameterType.GetOrPost);
    }

    RestResponse response = client.Execute(request);
    Console.WriteLine(response);
    if (response.StatusCode == System.Net.HttpStatusCode.OK)
    {
        JObject jsonObject = JObject.Parse(response.Content);
        accessToken = (string)jsonObject["access_token"];
        refreshToken = (string)jsonObject["refresh_token"];
        Console.WriteLine($"Token: {AccessToken}");
        Console.WriteLine($"Refresh_token: {RefreshToken} " + "\n");
    }
    else
    {
        Console.WriteLine(response.Content);
        Console.WriteLine("Failed to get access token. Status code: " + response.StatusCode);
    }
    return (accessToken, refreshToken);
}

解决方案

1. 修复Basic Auth头的正确性

你当前请求头中的Authorization: Basic dndmci1hcGktY2xpZW50Og==解码后为vwfr-api-client:,末尾带空密码,这和你使用的vwfr-trusted-api-client客户端ID不匹配。正确的做法是用client_id:client_secret的组合生成Base64编码:

// 替换原Authorization头的生成方式
var clientCredentials = "vwfr-trusted-api-client:5876d4ff-6434-40ce-9635-cf3920b240d1";
var base64Credentials = Convert.ToBase64String(Encoding.UTF8.GetBytes(clientCredentials));
request.AddHeader("Authorization", $"Basic {base64Credentials}");

同时移除表单参数中的client_id和client_secret——多数OAuth2密码模式服务要求客户端信息通过Basic Auth传递,而非表单。

2. 恢复遗漏的请求头

你代码中注释掉了X-IBM-Client-Id,但Postman截图中可能包含该头,需确认后添加:

request.AddHeader("X-IBM-Client-Id", "6cc43ffd-9818-43d4-b1d5-4d87fa5258de");

3. 简化RestSharp表单请求写法

RestSharp内置表单参数处理,无需手动编码:

private (string, string) GetAccessToken_RefreshToken()
{
    var request = new RestRequest(URL_TOKEN, Method.Post);
    // 设置表单编码类型
    request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
    request.AddHeader("Cache-Control", "no-cache");
    
    // 正确生成Basic Auth头
    var clientCredentials = "vwfr-trusted-api-client:5876d4ff-6434-40ce-9635-cf3920b240d1";
    var base64Credentials = Convert.ToBase64String(Encoding.UTF8.GetBytes(clientCredentials));
    request.AddHeader("Authorization", $"Basic {base64Credentials}");
    
    // 添加X-IBM-Client-Id头(如果Postman中存在)
    request.AddHeader("X-IBM-Client-Id", "6cc43ffd-9818-43d4-b1d5-4d87fa5258de");
    
    // 添加表单参数
    request.AddFormParameter("grant_type", "password");
    request.AddFormParameter("username", "SALESPERSON1");

    RestResponse response = client.Execute(request);
    Console.WriteLine(response.Content);
    
    if (response.StatusCode == System.Net.HttpStatusCode.OK)
    {
        JObject jsonObject = JObject.Parse(response.Content);
        accessToken = jsonObject["access_token"]?.ToString();
        refreshToken = jsonObject["refresh_token"]?.ToString();
        Console.WriteLine($"Token: {accessToken}");
        Console.WriteLine($"Refresh_token: {refreshToken}\n");
    }
    else
    {
        Console.WriteLine($"Failed to get access token. Status code: {response.StatusCode}");
    }
    return (accessToken, refreshToken);
}

4. 抓包对比请求差异

用Fiddler捕获Postman和代码的请求,对比以下内容:

  • 请求头的所有字段是否完全一致
  • 请求体的参数顺序、编码是否相同
  • 确认没有额外的字符或格式差异

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 11:07:32