c# REST API 中本机/桌面应用程序的 Keycloak 无法正常工作或者我遗漏了什么?

Keycloack for native /desktop application in c# REST APIs, not working properly or am I missing something?

只有当我已经打开浏览器并且已经登录时,我才能通过 keycloak 端点获取授权码和访问令牌,否则代码无法获取授权码。

所以考虑到我在应用程序启动时实现了这个逻辑(它不是确定的),我必须 运行 它 2 次才能获取代码,然后是令牌。

我只使用 rest API,因为我找不到可理解的用于桌面/本机应用程序的 keycloak 库。

这是我的代码:

public static async  Task<string>  GetTokenAsync()
    {
 
        string redirectURI = string.Format("http://{0}:{1}/", "localhost", GetRandomUnusedPort());
        string RedirectURIWithoutLastSlash = redirectURI.TrimEnd('/');
 
 
        string code = await GetCodeForAuthentication(redirectURI, RedirectURIWithoutLastSlash);
 
        UnityWebRequest request = new UnityWebRequest();
        request.url = $"https://tokenEndpoint.../protocol/openid-connect/token";
 
        request.method = UnityWebRequest.kHttpVerbPOST;
        request.downloadHandler = new DownloadHandlerBuffer();
       
 
 
        request.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded");
 
        string postData = "";
 
        Dictionary<string, string> postParameters = new Dictionary<string, string>() /
            {
                {"grant_type", "authorization_code"},
                {"code", code},
                {"client_id", "myID"},
                {"client_secret", "mySECRET"},
                {"redirect_uri", RedirectURIWithoutLastSlash }
            };
 
        foreach (string key in postParameters.Keys)
            postData += UnityWebRequest.EscapeURL(key) + "=" + UnityWebRequest.EscapeURL(postParameters[key]) + "&";
 
        byte[] data = Encoding.ASCII.GetBytes(postData);
 
        request.uploadHandler = new UploadHandlerRaw(data) ;
 
        request.timeout = 60;
 
        request.SendWebRequest();
 
        while (!request.isDone)
        {
            Debug.Log(request.downloadProgress);
        }
 
        Debug.Log("text by server is: " + request.downloadHandler.text);
 
        TokenClass token = JsonUtility.FromJson<TokenClass>(request.downloadHandler.text);
 
        access_token = token.access_token;
 
        tokenInfo = token;
        Debug.Log("access token is: " + access_token);
 
        return access_token;
    }
 
    private static async Task<string> GetCodeForAuthentication(string redirectURI, string RedirectURIWithoutLastSlash)
    {
 
     
 
        string code = null;
 
        HttpListener http = new HttpListener();
        http.Prefixes.Add(redirectURI);
        http.Start();
 
 
 
        string authorizationRequest = $"https://authCode Endpoint.../protocol/openid-connect/auth?client_id=myID&response_type=code&response_mode=query&scope=profile&redirect_uri={RedirectURIWithoutLastSlash}";
 
        // Opens request in the browser.
        Process web_Login_Process = new Process();
        web_Login_Process.StartInfo.FileName = GetSystemDefaultBrowser();
        web_Login_Process.StartInfo.Arguments = authorizationRequest;
        web_Login_Process.Start();
 
 
            try
            {
             
                var context = await http.GetContextAsync();
                var response = context.Response;
 
                var html = "<html><head><meta http-equiv='refresh' content='10;url=https://localhost'></head><body>Please return to the Digital Twin.</body></html>";
 
 
                string responseString = string.Format(html);
                var buffer = System.Text.Encoding.UTF8.GetBytes(responseString);
                response.ContentLength64 = buffer.Length;
                var responseOutput = response.OutputStream;
                Task responseTask = responseOutput.WriteAsync(buffer, 0, buffer.Length).ContinueWith((task) =>
                {
                    responseOutput.Close();
                    http.Stop();
                    Console.WriteLine("HTTP server stopped.");
                });
           
           
            // Checks for errors.
            if (context.Request.QueryString.Get("error") != null)
                {
                    string debug = context.Request.QueryString.Get("error");
 
                }
                if (context.Request.QueryString.Get("code") == null
                    || context.Request.QueryString.Get("state") == null)
                {
 
                    var debug = context.Request.QueryString; //no keys, Lenght is equal to 0
 
                    var debug3 = context.Request.RawUrl; // favicon.ico is the result
 
 
                }
                // extracts the code
                code = context.Request.QueryString.Get("code");
 
                string tryCode = context.Request.QueryString["code"];
 
                Debug.Log("code is: " + code);
 
               
 
            }
            catch (Exception ex)
            {
                string g = ex.Message;
            }
 
        return code;
    }

如有任何帮助,我们将不胜感激。

有一个 C# Sample 您可以遵循桌面流程并从中借鉴一些想法。请注意,控制台应用程序的 OAuth 流程与桌面应用程序相同。

您应该使用 PKCE 来确保桌面应用程序的安全性,上面的库将为您实现这一点

要与正确的 OAuth 行为进行比较,请参阅我的这些资源: