Vac*_*ano 6 c# curl .net-core .net-core-3.1
这似乎是一个很遥远的事情。但我看到几个答案表明,当 .Net Core 应用程序中需要 cURL 时,应该使用 HttpClient (和类似的)。
我有以下 cURL 命令(完美运行):
curl -v -L --negotiate -u : -b ~/cookiejar.txt "https://idp.domain.net/oauth2/authorize?scope=openid&response_type=code&redirect_uri=https://localhost:5001&client_id=client_id_here"
Run Code Online (Sandbox Code Playgroud)
该命令的流程如下:
-L选项在那里,所以它遵循重定向www-authenticate:Negotiate标头的 401(未经授权)。www-authenticate:Negotiate标头并从操作系统获取 Kerberos 令牌(因为--negotiate和-u选项)。Authorization: Negotiate <kerberos token here>.-b选项,cURL 会拾取 cookie。-b选项再次被选中。)全部写下来,让它在 .Net 应用程序中运行似乎是一项严肃的任务。但我想我会问一下它是否内置在框架中的某个地方。
是否有 .Net Core Framework 类(或类似的类)可以让我在 C# 代码中重现此 cURL 命令?
注意:我可以通过调用 powershell 来做到这一点。这个问题是关于用 来做的HttpClient。
我能够构建一个自定义目的方法来完成我需要的调用(以获取 OAuth 2 身份验证代码)。
Cookie 是自动添加的,但我是否添加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;
}
}
Run Code Online (Sandbox Code Playgroud)
如果您添加以下 NuGet 包,它将在 LinqPad 中运行:
我还有以下“使用”声明:
系统
系统.集合
系统.集合.通用
系统数据
系统诊断
系统IO
系统Linq
System.Linq.Expressions
系统.反射
系统.文本
系统.文本.正则表达式
系统线程
系统.交易
系统.Xml
系统.Xml.Linq
系统.Xml.XPath
Kerberos.NET
Kerberos.NET.客户端
Kerberos.NET.凭据
Kerberos.NET.实体
Kerberos.NET.Win32
Microsoft.Extensions.DependencyInjection
Microsoft.Extensions.Http
系统网
系统.Net.Http
System.Net.Http.Headers
系统.线程.任务
系统.Web