C# 在.Net Core 3.1中使用重定向和Cookies复制cURL命令
这一个似乎不太可能。但我看到了一些答案,它们表明当.Net核心应用程序需要cURL时,应该使用HttpClient(以及类似的) 我有以下cURL命令(非常有效): 此命令的流程如下所示:C# 在.Net Core 3.1中使用重定向和Cookies复制cURL命令,c#,curl,.net-core,.net-core-3.1,C#,Curl,.net Core,.net Core 3.1,这一个似乎不太可能。但我看到了一些答案,它们表明当.Net核心应用程序需要cURL时,应该使用HttpClient(以及类似的) 我有以下cURL命令(非常有效): 此命令的流程如下所示: 加载提供的url() 获取要重定向到的302响应 因为有-L选项,所以它遵循重定向 重定向用带有www-authenticate:Negotiate头的401(未经授权)响应 cURL看到www-authenticate:Negotiate头并从操作系统获取Kerberos令牌(因为--Negotiat
- 因为有
选项,所以它遵循重定向-L
www-authenticate:Negotiate
头的401(未经授权)响应www-authenticate:Negotiate
头并从操作系统获取Kerberos令牌(因为--Negotiate
和-u
选项)Authorization:Negotiate
- 由于
选项,cookie由cURL拾取-b
-b
选项,再次拾取。)HttpClient
将curl标志转换为HttpClient
-L
HttpClient
应自动遵循重定向,因为
--协商-u:
HttpClient
将处理协商,如果您为其构造函数提供了一个提供凭据的HttpClientHandler
。由于您将默认Windows凭据与-u:
一起使用,因此可以从以下位置使用代码:
-b~/cookiejar.txt
HttpClient
可以通过向其构造函数提供一个HttpClientHandler
来存储cookie,方法是:
这取决于HttpClientHandler
返回内容
您可以使用和来读取HttpClient的响应
var response = await client.GetAsync("");
var content = await response.Content.ReadAsStringAsync();
一切结合在一起
如果我们显式地设置上面引用的每个值,那么构建HttpClient
并发出等效请求应该是这样的:
var client = new HttpClient(
new HttpClientHandler()
{
// -L
AllowAutoRedirect = true,
// --negotiate -u :
UseDefaultCredentials = true,
// -b ~/cookiejar.txt
CookieContainer = new CookieContainer(),
UseCookies = true
}
);
var response = await client.GetAsync("https://idp.domain.net/oauth2/authorize?scope=openid&response_type=code&redirect_uri=https://localhost:5001&client_id=client_id_here");
var content = await response.Content.ReadAsStringAsync();
我能够构建一个自定义方法来完成我需要的调用(以获得OAuth 2身份验证代码)
Cookies是自动添加的,但我是否添加了CookieContainer
和UseCookies
设置似乎并不重要
而且,UseDefaultCredentials
似乎也没有做任何事情
async Task Main()
{
var services = new ServiceCollection();
services.AddHttpClient("OAuthClient").ConfigurePrimaryHttpMessageHandler(() => new AuthenticationHandler());;
var serviceProvider = services.BuildServiceProvider();
var httpClientFactory = serviceProvider.GetService<IHttpClientFactory>();
var authCodeUrl = "https://idp.domain.net/oauth2/authorize?scope=openid&response_type=code&redirect_uri=https://localhost:5001&client_id=client_id_here";
var authNegotiator = new AuthenticaitonNegotiator(httpClientFactory);
var authCode = await authNegotiator.GetAuthorizationCodeViaKerberosIwa(authCodeUrl);
Console.WriteLine(authCode);
}
public class AuthenticaitonNegotiator
{
private IHttpClientFactory httpClientFactory;
public AuthenticaitonNegotiator(IHttpClientFactory httpClientFactory)
{
this.httpClientFactory = httpClientFactory;
}
public async Task<string> GetAuthorizationCodeViaKerberosIwa(string authCodeUrl)
{
var kerberosToken = GetKerberosTokenViaIwa();
var authCode = await GetAuthorizationCodeViaKerberos(authCodeUrl, kerberosToken);
return authCode;
}
public async Task<string> GetAuthorizationCodeViaKerberosCredsAsync(string authCodeUrl, string username, string password)
{
var kerberosToken = await GetKerberosTokenViaCredsAsync(username, password);
var authCode = await GetAuthorizationCodeViaKerberos(authCodeUrl, kerberosToken);
return authCode;
}
public async Task<string> GetAuthorizationCodeViaKerberos(string authCodeUrl, string kerberosToken)
{
var httpClient = httpClientFactory.CreateClient("OAuthClient");
var done = false;
string currentUrl = authCodeUrl;
string responseText = "";
bool wasSuccessful = false;
while (!done)
{
var response = await httpClient.GetAsync(currentUrl);
responseText = await response.Content.ReadAsStringAsync();
// Reset the authenticaiton header if it was set. (It gets set as needed on each iteration.)
httpClient.DefaultRequestHeaders.Authorization = null;
if (response.StatusCode == HttpStatusCode.Unauthorized
&& response.Headers.Any(x => x.Key == "WWW-Authenticate" && x.Value.Contains("Negotiate")))
{
currentUrl = response.RequestMessage.RequestUri.AbsoluteUri;
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Negotiate", kerberosToken);
}
else if (response.StatusCode == HttpStatusCode.Redirect)
{
var redirectUri = response.Headers.Location;
var query = HttpUtility.ParseQueryString(redirectUri.Query);
var code = query.Get("code");
if (code == null)
{
currentUrl = redirectUri.AbsoluteUri;
}
else
{
// If this is the last redirect where we would send to the callback, just grab the auth code.
// This saves us from needing to host a service to handle the callback.
responseText = code;
done = true;
wasSuccessful = true;
}
}
else
{
done = true;
wasSuccessful = false;
}
}
if (wasSuccessful == false)
{
throw new ApplicationException($"Failed to retrive authorization code: \r\n {responseText}");
}
return responseText;
}
public async Task<String> GetKerberosTokenViaCredsAsync(string username, string password)
{
var client = new KerberosClient();
var kerbCred = new KerberosPasswordCredential(username, password, "YourDomain.net");
await client.Authenticate(kerbCred);
var ticket = await client.GetServiceTicket("http/ServerToGetTheKerberosToken.YourDomain.net");
return Convert.ToBase64String(ticket.EncodeGssApi().ToArray());
}
public string GetKerberosTokenViaIwa()
{
string token = "";
using (var context = new SspiContext($"http/ServerToGetTheKerberosToken.YourDomain.net", "Negotiate"))
{
var tokenBytes = context.RequestToken();
token = Convert.ToBase64String(tokenBytes);
}
return token;
}
}
public class AuthenticationHandler : HttpClientHandler
{
public AuthenticationHandler()
{
// cURL Equivilant: -L
AllowAutoRedirect = true;
MaxAutomaticRedirections = 100;
// cURL Equivilant: --negotiate -u :
UseDefaultCredentials = true;
// cURL Equivilant: -b ~/cookiejar.txt
CookieContainer = new CookieContainer();
UseCookies = true;
}
}
async Task Main()
{
var services=newservicecolection();
services.AddHttpClient(“OAuthClient”).ConfigurePrimaryHttpMessageHandler(()=>new AuthenticationHandler());;
var serviceProvider=services.BuildServiceProvider();
var httpClientFactory=serviceProvider.GetService();
var authCodeUrl=”https://idp.domain.net/oauth2/authorize?scope=openid&response_type=code&redirect_uri=https://localhost:5001&client_id=client_id_here";
var authCongregator=新的身份验证连接器(httpClientFactory);
var authCode=await authCongregator.GetAuthorizationCodeViaKerberosIwa(authCodeUrl);
Console.WriteLine(authCode);
}
公共类身份验证连接器
{
私人IHttpClientFactory httpClientFactory;
公共身份验证连接器(IHttpClientFactory httpClientFactory)
{
this.httpClientFactory=httpClientFactory;
}
公共异步任务GetAuthorizationCodeViaKerberosIwa(字符串authCodeUrl)
{
var kerberosToken=GetKerberosTokenViaIwa();
var authCode=等待GetAuthorizationCodeViaKerberos(authCodeUrl,kerberosToken);
返回认证码;
}
公共异步任务GetAuthorizationCodeViaKerberosCredsAsync(字符串authCodeUrl、字符串用户名、字符串密码)
{
var kerberosToken=等待getkerberostokenviacredasync(用户名、密码);
var authCode=等待GetAuthorizationCodeViaKerberos(authCodeUrl,kerberosToken);
返回认证码;
}
公共异步任务GetAuthorizationCodeViaKerberos(字符串authCodeUrl,字符串kerberosToken)
{
var httpClient=httpClientFactory.CreateClient(“OAuthClient”);
var done=false;
字符串currentUrl=authCodeUrl;
字符串responseText=“”;
布尔成功=假;
而(!完成)
{
var response=wait httpClient.GetAsync(currentUrl);
responseText=wait response.Content.ReadAsStringAsync();
//如果已设置,则重置AuthenticationOn标头。(在每次迭代中根据需要进行设置。)
httpClient.DefaultRequestHeaders.Authorization=null;
如果(response.StatusCode==HttpStatusCode.Unauthorized
&&response.Headers.Any(x=>x.Key==“WWW-Authenticate”&&x.Value.Contains(“协商”))
var response = await client.GetAsync("");
var content = await response.Content.ReadAsStringAsync();
var client = new HttpClient(
new HttpClientHandler()
{
// -L
AllowAutoRedirect = true,
// --negotiate -u :
UseDefaultCredentials = true,
// -b ~/cookiejar.txt
CookieContainer = new CookieContainer(),
UseCookies = true
}
);
var response = await client.GetAsync("https://idp.domain.net/oauth2/authorize?scope=openid&response_type=code&redirect_uri=https://localhost:5001&client_id=client_id_here");
var content = await response.Content.ReadAsStringAsync();
async Task Main()
{
var services = new ServiceCollection();
services.AddHttpClient("OAuthClient").ConfigurePrimaryHttpMessageHandler(() => new AuthenticationHandler());;
var serviceProvider = services.BuildServiceProvider();
var httpClientFactory = serviceProvider.GetService<IHttpClientFactory>();
var authCodeUrl = "https://idp.domain.net/oauth2/authorize?scope=openid&response_type=code&redirect_uri=https://localhost:5001&client_id=client_id_here";
var authNegotiator = new AuthenticaitonNegotiator(httpClientFactory);
var authCode = await authNegotiator.GetAuthorizationCodeViaKerberosIwa(authCodeUrl);
Console.WriteLine(authCode);
}
public class AuthenticaitonNegotiator
{
private IHttpClientFactory httpClientFactory;
public AuthenticaitonNegotiator(IHttpClientFactory httpClientFactory)
{
this.httpClientFactory = httpClientFactory;
}
public async Task<string> GetAuthorizationCodeViaKerberosIwa(string authCodeUrl)
{
var kerberosToken = GetKerberosTokenViaIwa();
var authCode = await GetAuthorizationCodeViaKerberos(authCodeUrl, kerberosToken);
return authCode;
}
public async Task<string> GetAuthorizationCodeViaKerberosCredsAsync(string authCodeUrl, string username, string password)
{
var kerberosToken = await GetKerberosTokenViaCredsAsync(username, password);
var authCode = await GetAuthorizationCodeViaKerberos(authCodeUrl, kerberosToken);
return authCode;
}
public async Task<string> GetAuthorizationCodeViaKerberos(string authCodeUrl, string kerberosToken)
{
var httpClient = httpClientFactory.CreateClient("OAuthClient");
var done = false;
string currentUrl = authCodeUrl;
string responseText = "";
bool wasSuccessful = false;
while (!done)
{
var response = await httpClient.GetAsync(currentUrl);
responseText = await response.Content.ReadAsStringAsync();
// Reset the authenticaiton header if it was set. (It gets set as needed on each iteration.)
httpClient.DefaultRequestHeaders.Authorization = null;
if (response.StatusCode == HttpStatusCode.Unauthorized
&& response.Headers.Any(x => x.Key == "WWW-Authenticate" && x.Value.Contains("Negotiate")))
{
currentUrl = response.RequestMessage.RequestUri.AbsoluteUri;
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Negotiate", kerberosToken);
}
else if (response.StatusCode == HttpStatusCode.Redirect)
{
var redirectUri = response.Headers.Location;
var query = HttpUtility.ParseQueryString(redirectUri.Query);
var code = query.Get("code");
if (code == null)
{
currentUrl = redirectUri.AbsoluteUri;
}
else
{
// If this is the last redirect where we would send to the callback, just grab the auth code.
// This saves us from needing to host a service to handle the callback.
responseText = code;
done = true;
wasSuccessful = true;
}
}
else
{
done = true;
wasSuccessful = false;
}
}
if (wasSuccessful == false)
{
throw new ApplicationException($"Failed to retrive authorization code: \r\n {responseText}");
}
return responseText;
}
public async Task<String> GetKerberosTokenViaCredsAsync(string username, string password)
{
var client = new KerberosClient();
var kerbCred = new KerberosPasswordCredential(username, password, "YourDomain.net");
await client.Authenticate(kerbCred);
var ticket = await client.GetServiceTicket("http/ServerToGetTheKerberosToken.YourDomain.net");
return Convert.ToBase64String(ticket.EncodeGssApi().ToArray());
}
public string GetKerberosTokenViaIwa()
{
string token = "";
using (var context = new SspiContext($"http/ServerToGetTheKerberosToken.YourDomain.net", "Negotiate"))
{
var tokenBytes = context.RequestToken();
token = Convert.ToBase64String(tokenBytes);
}
return token;
}
}
public class AuthenticationHandler : HttpClientHandler
{
public AuthenticationHandler()
{
// cURL Equivilant: -L
AllowAutoRedirect = true;
MaxAutomaticRedirections = 100;
// cURL Equivilant: --negotiate -u :
UseDefaultCredentials = true;
// cURL Equivilant: -b ~/cookiejar.txt
CookieContainer = new CookieContainer();
UseCookies = true;
}
}