Table of Contents

Авторизации в C# .NET

Пример обращения к web-серверу, получения и обработки результата реализован на языке C#[7] в среде .NET[8] версии 8.0.13.

Взаимодействие с сервером осуществляется через объект класса HttpClient[9].

Классы объектов, отправляемых в запросах и получаемых в ответах, берутся из библиотек ПОЛИНОМ:MDM Polynom.Web.Api.Data и Polynom.Web.Api.Models.

ВНИМАНИЕ: применяемость токена входа истекает через 10 минут после его создания. Для продолжения работы нужно использовать токен обновления.

Создание Http-клиента

// Получаем адрес сервера
var serverAddress = "http://localhost:5000";

// Проверяем адрес сервера
if (!Uri.TryCreate(serverAddress, UriKind.Absolute, out var baseAddress))
    throw new ArgumentException("Ошибка адреса web-сервера ПОЛИНОМ:MDM");

// Создаем экземпляр класса HttpClient
var client = new HttpClient()
{
    BaseAddress = baseAddress
};

Получение списка зарегистрированных хранилищ

Определение StorageDefinitionResponse

/// <summary>
/// Модель данных ответа на запрос описаний хранилищ.
/// </summary>
public class StorageDefinitionResponse
{
    /// <summary>
    /// Идентификатор хранилища.
    /// </summary>
    public Guid StorageId { get; set; }

    /// <summary>
    /// Отображаемое имя хранилища.
    /// </summary>
    public string DisplayName { get; set; } = null!;
}

Запрос и чтение ответа:

// Запрашиваем описание хранилищ
List<StorageDefinitionResponse> storages;
using (var response = await client.GetAsync("api/v1/login/storage-definitions", CancellationToken.None))
{
    response.EnsureSuccessStatusCode();
    storages = await response.Content.ReadFromJsonAsync<List<StorageDefinitionResponse>>(
        cancellationToken: CancellationToken.None) ?? new List<StorageDefinitionResponse>();
}

var storageId = storages.FirstOrDefault(c => c.DisplayName == storageName)?.StorageId ??
                throw new Exception("Хранилище не найдено");

Вход

Определение SignInRequest

/// <summary>
/// Тип клиентов ПОЛИНОМ:MDM.
/// </summary>
public enum ClientTypes : byte
{
    /// <summary>
    /// Нет типа.
    /// </summary>
    None = 0,

    /// <summary>
    /// Клиент.
    /// </summary>
    Client = 8,

    /// <summary>
    /// Конвертер.
    /// </summary>
    Importer = 16,

    /// <summary>
    /// Редактор.
    /// </summary>
    Editor = 32,

    /// <summary>
    /// Администратор.
    /// </summary>
    Administrator = 64
}

/// <summary>
/// Модель данных для авторизации пользователя
/// </summary>
public class SignInRequest
{
    /// <summary>
    /// Идентификатор хранилища.
    /// </summary>
    public string StorageId { get; set; } = null!;

    /// <summary>
    /// Имя пользователя ПОЛИНОМ:MDM.
    /// </summary>
    public string? Login { get; set; }

    /// <summary>
    /// Пароль.
    /// </summary>
    public string? Password { get; set; }

    /// <summary>
    /// Имя модуля.
    /// </summary>
    public string? ModuleName { get; set; }

    /// <summary>
    /// Указывает тип клиента.
    /// </summary>
    public ClientTypes? ClientType { get; set; }
}

Определение AuthResponse

/// <summary>
/// Ответ на авторизацию пользователя.
/// </summary>
public class AuthResponse
{
    /// <summary> Токен доступа. </summary>
    [JsonPropertyName("access_token")]
    public string AccessToken { get; set; } = string.Empty;

    /// <summary> Тип токена доступа. </summary>
    [JsonPropertyName("token_type")]
    public string TokenType { get; set; } = "Bearer";

    /// <summary> Срок жизни токена доступа. (сек.) </summary>
    [JsonPropertyName("expires_in")]
    public int ExpiresIn { get; set; } = 600;

    /// <summary> Токен обновления токена доступа. </summary>
    [JsonPropertyName("refresh_token")]
    public string? RefreshToken { get; set; } = string.Empty;
}

Запрос и чтение ответа:

var signInRequest = new SignInRequest()
{
    Login = username,
    Password = password,
    StorageId = storageId.ToString(),
    ClientType = ClientType.Client
};

AuthResponse? authResponse;
using (var jsonContent = JsonContent.Create(signInRequest))
{
    using (var response = await client.PostAsync(@"api/v1/login/sign-in", jsonContent, CancellationToken.None))
    {
        response.EnsureSuccessStatusCode();

        authResponse =
            await response.Content.ReadFromJsonAsync<AuthResponse>(cancellationToken: CancellationToken.None);

        if (authResponse is null)
            throw new Exception("Ошибка получения данных ответа");
    }
}

Сохранение токена для последующих запросов

Чтобы отправлять запросы web-серверу ПОЛИНОМ:MDM, нужно добавить полученный ранее токен в заголовки запроса.

client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", authResponse.AccessToken);

Обновление токена входа

Запрос и чтение ответа:

// Обновление токена авторизации
using (var textContent = new StringContent(authResponse.RefreshToken, Encoding.UTF8, MediaTypeNames.Text.Plain))
{
    // Обрабатываем ответ
    using (var response = await client.PatchAsync("api/v1/login/update-token", textContent,
               cancellationToken: CancellationToken.None))
    {
        response.EnsureSuccessStatusCode();
        authResponse =
            await response.Content.ReadFromJsonAsync<AuthResponse>(cancellationToken: CancellationToken.None);

        if (authResponse is null)
            throw new Exception("Ошибка получения данных ответа");

        client.DefaultRequestHeaders.Authorization =
            new AuthenticationHeaderValue(authResponse.TokenType, authResponse.AccessToken);
    }
}

Выход

Запрос и чтение ответа:

using (var response = await client.DeleteAsync("api/v1/login/sign-out"))
{
    response.EnsureSuccessStatusCode();
}

См. пример Samples.WebApi.Authorization

Ссылки

  1. Руководство по C# — управляемый язык .NET. (дата обращения: 16.07.2024).
  2. Загрузите .NET 8.0 (Linux, macOS и Windows). (дата обращения: 16.07.2024).
  3. HttpClient Class (System.Net.Http). (дата обращения: 16.07.2024).