Search code examples
c#.netoauth-2.0windows-servicesabp-framework

How to send request from Windows Service to ABP Framework?


I'm trying to create a Windows Service that sends data to the ABP Framework API. I learned that in order to access the API, you need to log in. In the ABP Framework, authorization occurs using OAuth 2. I created a console application that logs in and sends data to the API, everything works well, then I used nmss.exe to create a Windows Service from my console application, but unfortunately this does not work.

1) ConsoleServerApplication

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RestSharp;
using RestSharp.Authenticators.OAuth2;
using System.Net;
using System.Text;

namespace NewServerProject
{
    public class Program
    {
        static async Task Main(string[] args)
        {
            using var listener = new HttpListener();
            listener.Prefixes.Add("http://localhost:8001/");
            listener.Start();

            while (true)
            {
                var context = listener.GetContext();
                var request = context.Request;
                if (request.HttpMethod == "POST")
                {
                    await PostRequestFromGate(request, context);

                    context.Response.Close();
                }
            }
        }

        static async Task PostRequestFromGate(HttpListenerRequest request, HttpListenerContext context)
        {
            string text;
            using (var reader = new StreamReader(request.InputStream,
                                                 request.ContentEncoding))
            {
                text = reader.ReadToEnd();
            }
            await PostRequestToAPI(text);

        }

        static async Task PostRequestToAPI(string text)
        {
            string clientId = "CM_Postman";
            string clientSecret = "3284687Egor";
            string redirectUri = "https://localhost:44318/swagger/oauth2-redirect.html";
            string authorizationEndpoint = "https://localhost:44350/connect/authorize";
            string scope = "TestProject";
            string tokenEndpoint = "https://localhost:44350/connect/token";

            string authorizationCode = GetAuthorizationCode(authorizationEndpoint, clientId, redirectUri, scope);
            string accessTokfen = GetAuthToken(tokenEndpoint, clientId, clientSecret, authorizationCode, redirectUri);
            await GetData(accessTokfen, text);
        }

        static string GetAuthorizationCode(string authorizationEndpoint, string clientId, string redirectUri, string scope)
        {

            string authorizationUrl = $"{authorizationEndpoint}?client_id={clientId}&redirect_uri={redirectUri}&scope={scope}&response_type=code";

            
            return PostToSupportApp(authorizationUrl).Result;
        }

        public record JsonClass(string url);
        static async Task<string> PostToSupportApp(string url)
        {
            JsonClass jsonClass = new(url);
            string jsonString = JsonConvert.SerializeObject(jsonClass);
            var client = new RestClient("http://localhost:8003/");
            var request = new RestRequest()
            {
                Method = Method.Post
            };
            request.AddHeader("Content-Type", "application/json");
            request.AddHeader("Accept", "application/json");
            request.AddParameter("application/json", jsonString, ParameterType.RequestBody);
            RestResponse response = client.Execute(request);
            foreach (var f in response.Headers)
            {
                if (f.Name.ToString() == "code")
                {
                    return f.Value.ToString();
                }
            }
            return null;
        }
        public record Token(string access_token, string token_type, int expires_in, string scope);
        static string GetAuthToken(string tokenEndpoint, string clientId,
string clientSecret, string authorizationCode, string redirectUri)
        {
            var client = new RestClient(tokenEndpoint);
            var request = new RestRequest()
            {
                Method = Method.Post
            };
            request.AddParameter("grant_type", "authorization_code");
            request.AddParameter("code", authorizationCode);
            request.AddParameter("redirect_uri", redirectUri);
            request.AddParameter("username", "admin");
            request.AddParameter("password", "1q2w3E*");
            request.AddParameter("client_id", clientId);
            request.AddParameter("client_secret", clientSecret);

            RestResponse response = client.Execute(request);

            Token token = System.Text.Json.JsonSerializer.Deserialize<Token>(response.Content.ToString());
            // Extract and return the access token
            return token.access_token;
        }
        static async Task GetData(string accesToken, string jsodata)
        {
            string apiEndpoint = "https://localhost:44318/api/app/check-ins/datanew";
            var authenticator = new OAuth2AuthorizationRequestHeaderAuthenticator(
    accesToken, "Bearer"
);
            var options = new RestClientOptions(apiEndpoint)
            {
                Authenticator = authenticator
            };
            var client = new RestClient(options);
            var request = new RestRequest()
            {
                Method = Method.Post
            };
            request.AddJsonBody(jsodata);

            RestResponse response = client.Execute(request);

        }
    }
}

2) SupportConsoleApp (Since Windows service does not have an interface and opening applications using it is not a good practice, I created 3 applications that will receive “CODE” to obtain a token in the future) To receive a CODE, you must first log in, after successful authorization we receive a redirect in the link of which our “CODE” is located and using Web Scraping I extract it from the link and send it to ConsoleServerApplication.

enter image description here

Does anyone know how to solve this problem? I think this has something to do with restricting access to Windows services


Solution

  • My problem was that, for some reason, the Windows service did not want to give access to the application due to the SSL certificate, so I scoured the Internet for a couple of days and found a solution that helped me

                using (HttpClient client = new HttpClient(new HttpClientHandler
                {
                    ServerCertificateCustomValidationCallback = (a, b, c, d) => true
                }))
    

    I disable the certificate when sending the request and it works.