使用来自 Windows 服务的 OpenID 连接通过 API 进行身份验证

Authenticate with API using OpenID connect from a Windows Service

我即将进行云迁移,我们之前在本地数据库之间传输数据方面做了很多工作。云提供商正在构建 API 以便我们在数据库进入云端后与它进行交互,所以我正在尝试编写一个 Windows 服务,该服务会定期从我们的其他服务器上吸取一些数据-prem db 和 post 它到云数据库。我无法弄清楚如何在 windows 服务中用 c# 实现 OpenID Connect 身份验证。我见过的所有示例都是 Web 应用程序。有人试过吗?

如果有人有比 windows 服务更好的主意,我愿意接受。

您应该寻找的是客户端凭据流(OpenID Connect 的一部分)。这是您在请求令牌时没有用户参与时使用的流程。

要获取令牌,您可以使用 IdentityModel 帮助程序库,您可以找到示例代码 here:

如果您不想使用 windows 服务,则另一种方法是创建一个控制台应用程序,您可以使用 windows 内置的任务调度程序来安排调用该应用程序。 或者,看看 HangFire.

我已与 API 通话。基本流程是您请求 Bearer 令牌,然后在相应的请求中传递令牌。这是我用来请求令牌的函数示例:

public static async Task<string> RequestTokenAsync()
    {
        var client = new HttpClient();
        string token;
        var con = new List<KeyValuePair<string, string>>
        {
            new KeyValuePair<string, string>("client_id", "XXXXX"),
            new KeyValuePair<string, string>("client_secret", "XXXXX"),
            new KeyValuePair<string, string>("grant_type", "password"),
            new KeyValuePair<string, string>("username", "XXXXX"),
            new KeyValuePair<string, string>("password", "XXXXX"),
            new KeyValuePair<string, string>("device_id", "XXXXX"),
            new KeyValuePair<string, string>("company", "XXXXX")
        };

        var request = new HttpRequestMessage
        {
            Method = HttpMethod.Post,
            RequestUri = new Uri("https://whatever/connect/token"),
            Content = new FormUrlEncodedContent(con)
            {
                Headers =
                {
                    ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded")
                }
            }
        };
        try
        {
            using (var response = await client.SendAsync(request))
            {
                response.EnsureSuccessStatusCode();
                var body = await response.Content.ReadAsStringAsync();
                token = body;
            }
        }
        catch (Exception ex)
        {
            return "ERROR: " + ex.Message;
        }

        Dictionary<string, object> values =
            JsonConvert.DeserializeObject<Dictionary<string, object>>(token);
        values.TryGetValue("access_token", out object extractedToken);

        return extractedToken.ToString();
    }

下面是使用令牌的示例:

public static async Task<List<Location>> GetLocations()
    {
        List<Location> result = new List<Location>();

        string jsonResponse;
        var client = new HttpClient();
        string token = await RequestTokenAsync();
        var request = new HttpRequestMessage
        {
            Method = HttpMethod.Get,
            RequestUri = new Uri("https://whatever/v1/Locations"),
        };
        request.Headers.TryAddWithoutValidation("Authorization", "Bearer " + token);
        try
        {
            using (var response = await client.SendAsync(request))
            {
                response.EnsureSuccessStatusCode();
                var body = await response.Content.ReadAsStringAsync();

                jsonResponse = body.ToString();
                try
                {
                    result = JsonConvert.DeserializeObject<List<Location>>(jsonResponse);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message + ex.StackTrace);
                }
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message + ex.StackTrace);
        }

        return result;
    }