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请求详情
请求体

请求头

尝试的代码及错误
初始代码实现
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
相关产品推荐
相关产品推荐

