且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

在 .Net Core 3.1 中使用重定向和 Cookie 复制 cURL 命令

更新时间:2023-02-15 13:30:57

我能够构建一个自定义用途的方法来完成我需要的调用(以获取 OAuth 2 身份验证代码).

I was able to build a custom purpose method that completed the call I needed (to get an OAuth 2 Auth Code).

Cookies 是自动添加的,但我是否添加了 CookieContainerUseCookies 设置似乎并不重要.

The Cookies got added automatically, but it did not seem to matter if I added the CookieContainer and UseCookies settings or not.

此外,UseDefaultCredentials 似乎也没有做任何事情.

Also, UseDefaultCredentials did not seem to do anything either.

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: 
 {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;
    }

}

如果您添加以下 NuGet 包,这将在 LinqPad 中运行:

This runs in LinqPad if you add the following NuGet Packages:

  • Kerberos.NET
  • Microsoft.Extensions.DependencyInjection
  • Microsoft.Extensions.Http

我也有以下使用"声明:

I also had the following "using" statements:

  • 系统

System.Collections

System.Collections

System.Collections.Generic

System.Collections.Generic

系统数据

系统诊断

System.IO

System.Linq

System.Linq

System.Linq.Expressions

System.Linq.Expressions

系统反射

系统文本

System.Text.RegularExpressions

System.Text.RegularExpressions

系统线程

系统事务

系统.Xml

System.Xml.Linq

System.Xml.Linq

System.Xml.XPath

System.Xml.XPath

Kerberos.NET

Kerberos.NET

Kerberos.NET.Client

Kerberos.NET.Client

Kerberos.NET.Credentials

Kerberos.NET.Credentials

Kerberos.NET.Entities

Kerberos.NET.Entities

Kerberos.NET.Win32

Kerberos.NET.Win32

Microsoft.Extensions.DependencyInjection

Microsoft.Extensions.DependencyInjection

Microsoft.Extensions.Http

Microsoft.Extensions.Http

System.Net

System.Net.Http

System.Net.Http

System.Net.Http.Headers

System.Net.Http.Headers

System.Threading.Tasks

System.Threading.Tasks

System.Web