【问题标题】:http get works in browser and postman but get a 401 using c# httpwebrequesthttp get 在浏览器和邮递员中工作,但使用 c# httpwebrequest 获得 401
【发布时间】:2017-07-22 23:11:24
【问题描述】:

我有一个托管在 azure 中的网络应用程序。当我使用邮递员提出请求时,我得到一个 json 结果,这是正确的响应。当我尝试使用相同的令牌通过 C# 发出相同的请求时,我收到一个 errpr - 远程服务器返回一个错误:(401) Unauthorized。

这是我用来发出请求的代码。

public string RequestData(string queryString, string token)
{
    var request = (HttpWebRequest)WebRequest.Create(queryString);
    request.Proxy = GetProxy();
    request.Credentials = CredentialCache.DefaultCredentials;
    request.PreAuthenticate = true;
    request.UseDefaultCredentials = true;
    request.Method = "GET";
    request.ContentType = "application/json";
    request.ContentLength = 0;
    request.CookieContainer = new CookieContainer();
    request.Headers.Add("authorization", "Bearer " + token);

    using (var webresponse = request.GetResponse())
    {
        if (webresponse.GetResponseStream() == Stream.Null)
        {
            throw new Exception("Response stream is empty");
        }

        var response = (HttpWebResponse)webresponse;

        if (response.StatusCode != HttpStatusCode.OK)
        {
            return response.StatusCode.ToString();
        }
        else
        {
            return response.StatusCode.ToString();
        }
    }
}

我已经仔细检查了令牌以确保它是正确的。 我想提的另一点是它最初在 没有启用拦截器的邮递员。这适用于 Advanced Rest Client。 在我启用“XHR”并安装 ARC cookie 交换之前,该请求不起作用。

我检查了 Fiddler 中的请求标头,发现除了授权标头(我也添加了)之外没有其他标头。

更新:

我在 Postman (https://www.getpostman.com/) 中收到了成功的回复 并使用 RestSharp 运行它为 c# 生成的代码。在回应中 抛出的错误是

“您无权查看此目录或页面。”

这表明令牌不正确。这是令人困惑的,因为它有效 在 Postman 和 Advanced Rest Client 中。另外我必须提到我检索令牌 在每次调用时使用 clientid 和 secret,使用以下代码:

   public async static Task<AzureAccessToken> CreateOAuthAuthorizationToken(string clientId, string clientSecret, string resourceId, string tenantId)
        {
            AzureAccessToken token = null;
            var oauthUrl=string.Format("https://login.microsoftonline.com/{0}/oauth2/token", tenantId);       
            var reqBody = String.Format("grant_type=client_credentials&client_id={0}&client_secret={1}",clientId, clientSecret);                 
            var client = new HttpClient();
            HttpContent content = new StringContent(reqBody);
            content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/x-www-form-urlencoded");
            using (HttpResponseMessage response = await client.PostAsync(oauthUrl, content))
            {
                if (response.IsSuccessStatusCode)
                {
                    DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(AzureAccessToken));
                    Stream json = await response.Content.ReadAsStreamAsync();
                    token = (AzureAccessToken)serializer.ReadObject(json);
                    return token;
                }    
                return null;
            }
        }

【问题讨论】:

  • 是的,仔细检查过
  • 在这种情况下,我认为您的代理正在阻止请求
  • 我也尝试过设置代理。如果我不设置代理,我会收到 407 错误。我在家里运行时也遇到同样的错误
  • @ThiagoCustodio,我认为您对令牌不正确的看法是正确的。即使它在 Postman 和 Advanced Rest Client 中工作。我已经发布了更多关于如何检索令牌的代码。将追溯我的步骤以确保发出正确的令牌。感谢您的 cmets。
  • 我推荐使用 Fiddler,然后你可以比较两个请求。

标签: c# azure asp.net-web-api


【解决方案1】:

我调用了第三方 API。当我使用邮递员发出请求时,我得到一个 json 结果,这是正确的响应。当我尝试使用相同的令牌通过 C# 发出相同的请求时,我收到一个错误 - 远程服务器返回一个错误:(401)未经授权。终于找到了解决办法。 当我发出登录请求时,服务器会发送一些 cookie,并且该 cookie 将存储在邮递员中。如果您看到代码 sn-p,您将看到有关邮递员提出的请求的信息。 当我调用 Login 方法时,我存储的 cookie 如下所示:

public ResponseData OnGetResponseFromAPI(string URL, string Method, string PostData = null, Dictionary<string, string> Headers = null, string body = null, string ContentType = "application/json")
    {
            ResponseData response = new ResponseData();
            try
        {
                
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
            var webRequest = (HttpWebRequest)WebRequest.Create(URL);
            CookieContainer cookieJar = new CookieContainer();
            webRequest.CookieContainer = cookieJar;
            webRequest.Method = Method;
            webRequest.ContentType = ContentType;
            if (Method == "GET")
            {
                var type = webRequest.GetType();
                var currentMethod = type.GetProperty("CurrentMethod", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(webRequest);
                var methodType = currentMethod.GetType();
                methodType.GetField("ContentBodyNotAllowed", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(currentMethod, false);
            }
            if (Headers == null)
                Headers = new Dictionary<string, string>();
            foreach (KeyValuePair<string, string> header in Headers)
            {
                webRequest.Headers.Add(header.Key, header.Value);
            }
            if (!string.IsNullOrEmpty(PostData))
            {
                var RequestStream = new StreamWriter(webRequest.GetRequestStream());
                RequestStream.Write(PostData);
                RequestStream.Close();
            }
            if (!string.IsNullOrEmpty(body))
            {
                byte[] byteArray = Encoding.UTF8.GetBytes(body);
                webRequest.ContentLength = byteArray.Length;
                Stream dataStream = webRequest.GetRequestStream();
                dataStream.Write(byteArray, 0, byteArray.Length);
                dataStream.Close();
            }
            var ResponseStream = new StreamReader(webRequest.GetResponse().GetResponseStream());               
                string cookie = string.Empty;
                CookieCollection allCookies = cookieJar.GetCookies(webRequest.RequestUri);                
                foreach (Cookie c in  allCookies)
                {
                    cookie = cookie + c.Name + "=" + c.Value+";";                   
                }
                cookie = cookie.Substring(0, cookie.LastIndexOf(';'));
                var ResponseData = ResponseStream.ReadToEnd();
                response.response=ResponseData.ToString();
                response.cookie=cookie;
            return response;
        }
        catch (WebException webException)
        {
            if (webException == null || webException.Response == null)
                return null;
            var responseStream = webException.Response.GetResponseStream() as MemoryStream;
            if (responseStream == null)
                return null;
            var responseBytes = responseStream.ToArray();
            var responseString = Encoding.UTF8.GetString(responseBytes);
            response.response = responseString;
            return response;
        }
    }

每当我调用任何 api 方法时,我都会在如下标头中发送令牌和 cookie:

public string DownLoadDocument( string FilePath, string FileName, string token,string cookie)
        {
            try
            {
                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;

               
                HttpWebRequest webRequest;
                webRequest = (HttpWebRequest)WebRequest.Create(URL);
                webRequest.Method = "GET";

                webRequest.ContentType = "application/octet-stream;charset=UTF-8";
                

                webRequest.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.1) Gecko/2008070208 Firefox/3.0.1";

                               
                webRequest.Headers.Add("Cookie", cookie);
                webRequest.Headers.Add("Authentication", "Bearer "+token);
                webRequest.Headers.Add("Content-Disposition", "attachment");
                                

                Stream responseReader = webRequest.GetResponse().GetResponseStream();                


                using (var fs = new FileStream(FilePath, FileMode.Create))
                {
                    responseReader.CopyTo(fs);

                }
            }
            catch (Exception ex)
            {

                throw;
            }           
            return FilePath;
        }

【讨论】:

  • 这没有提供问题的答案。一旦你有足够的reputation,你就可以comment on any post;相反,provide answers that don't require clarification from the asker。 - From Review
  • @JDOaktown:为什么会这样?
  • 如果有人遇到我在从 C# 调用第三方 api 时遇到的相同问题并且在邮递员中自动添加标题 @JDOaktown:while 调用这是必需的并且请阅读每个事物。在我的第三方 api 中,我错过了 cookie,如果您遇到任何问题,他们可以看到代码 sn-p 他们在发送身份验证时错过了什么。
【解决方案2】:

在azure中查看日志后,看到如下错误信息:

JWT 验证失败:IDX10214:受众验证失败。观众:'00000002-0000-0000-c000-000000000000'。不匹配:validationParameters.ValidAudience: 'f50a9d02-b8f4-408f-aaf8-0046e6cbf7a6' 或 validationParameters.ValidAudiences: 'null'。

我通过在 Azure Active Directory 设置下的“允许的令牌受众”中添加“00000002-0000-0000-c000-000000000000”解决了这个问题。

【讨论】:

    猜你喜欢
    • 2021-03-10
    • 2020-05-18
    • 2019-10-02
    • 2021-04-28
    • 1970-01-01
    • 2019-08-25
    • 2021-11-02
    • 2020-07-10
    • 1970-01-01
    相关资源
    最近更新 更多