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.
Does anyone know how to solve this problem? I think this has something to do with restricting access to Windows services
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.