vknet_vk/VkNet/Infrastructure/Authorization/ImplicitFlow/ImplicitFlow.cs
Инютин Максим Николаевич 3b145a3327 Рефакторинг проекта
2025-09-09 01:02:47 +03:00

243 lines
No EOL
6.8 KiB
C#

using System;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.Extensions.Logging;
using VkNet.Abstractions.Authorization;
using VkNet.Abstractions.Core;
using VkNet.Enums.StringEnums;
using VkNet.Exception;
using VkNet.Model;
using VkNet.Utils;
namespace VkNet.Infrastructure.Authorization.ImplicitFlow;
/// <inheritdoc cref="IImplicitFlow" />
public class ImplicitFlow : IImplicitFlow
{
/// <summary>
/// Логгер
/// </summary>
private readonly ILogger _logger;
/// <summary>
/// Менеджер версий VkApi
/// </summary>
private readonly IVkApiVersionManager _versionManager;
private IApiAuthParams _authorizationParameters;
[NotNull]
private readonly IAuthorizationFormFactory _authorizationFormsFactory;
private readonly IVkAuthorization<ImplicitFlowPageType> _vkAuthorization;
/// <inheritdoc cref="ImplicitFlow"/>
public ImplicitFlow(ILogger logger,
IVkApiVersionManager versionManager,
IAuthorizationFormFactory authorizationFormsFactory,
IVkAuthorization<ImplicitFlowPageType> vkAuthorization)
{
_logger = logger;
_versionManager = versionManager;
_authorizationFormsFactory = authorizationFormsFactory;
_vkAuthorization = vkAuthorization;
}
/// <inheritdoc />
public async Task<AuthorizationResult> AuthorizeAsync(CancellationToken token = default)
{
_logger.LogDebug("Валидация данных");
ValidateAuthorizationParameters();
_logger.LogDebug("Шаг 1. Открытие диалога авторизации");
var authorizeUrlResult = CreateAuthorizeUrl();
var loginFormResult = await _authorizationFormsFactory.Create(ImplicitFlowPageType.LoginPassword)
.ExecuteAsync(authorizeUrlResult, _authorizationParameters, token)
.ConfigureAwait(false);
return await NextStepAsync(loginFormResult, token)
.ConfigureAwait(false);
}
/// <inheritdoc />
public void SetAuthorizationParams(IApiAuthParams authorizationParams) => _authorizationParameters = authorizationParams;
/// <inheritdoc />
[Obsolete("Используйте перегрузку Url CreateAuthorizeUrl();\n"
+ "Параметры авторизации должны быть уставлены вызовом void SetAuthorizationParams(IApiAuthParams authorizationParams);")]
public Uri CreateAuthorizeUrl(ulong clientId, ulong scope, Display display, string state)
{
_authorizationParameters.ApplicationId = clientId;
_authorizationParameters.Display = display;
_authorizationParameters.State = state;
return CreateAuthorizeUrl();
}
/// <inheritdoc />
[Obsolete("Используйте перегрузку Url CreateAuthorizeUrl();\n"
+ "Параметры авторизации должны быть уставлены вызовом void SetAuthorizationParams(IApiAuthParams authorizationParams);")]
public Uri CreateAuthorizeUrl()
{
_logger.LogDebug("Построение url для авторизации");
const string url = "https://oauth.vk.ru/authorize?";
var vkAuthParams = new VkParameters
{
{
"client_id", _authorizationParameters.ApplicationId
},
{
"redirect_uri", _authorizationParameters.RedirectUri != null
? _authorizationParameters.RedirectUri.ToString()
: Constants.DefaultRedirectUri
},
{
"display", Display.Mobile
},
{
"scope", _authorizationParameters.Settings?.ToUInt64()
},
{
"response_type", ResponseType.Token
},
{
"v", _versionManager.Version
},
{
"state", _authorizationParameters.State
},
{
"revoke", _authorizationParameters.Revoke
}
};
var resultUrl = Url.Combine(url, Url.QueryFrom(vkAuthParams.ToArray()));
return new(Uri.UnescapeDataString(resultUrl));
}
private async Task<AuthorizationResult> NextStepAsync(AuthorizationFormResult formResult, CancellationToken token)
{
var requestUrl = formResult.RequestUrl;
if (requestUrl.OriginalString.StartsWith("https://oauth.vk.ru/auth_redirect"))
{
requestUrl = GetRedirectUrl(requestUrl);
}
var pageType = _vkAuthorization.GetPageType(requestUrl);
switch (pageType)
{
case ImplicitFlowPageType.Error:
{
_logger.LogError("При авторизации произошла ошибка");
throw new VkAuthorizationException("При авторизации произошла ошибка.");
}
case ImplicitFlowPageType.LoginPassword:
{
_logger.LogDebug("Неверный логин или пароль");
throw new VkAuthorizationException("Неверный логин или пароль.");
}
case ImplicitFlowPageType.Captcha:
{
_logger.LogDebug("Капча");
break;
}
case ImplicitFlowPageType.TwoFactor:
{
_logger.LogDebug("Двухфакторная авторизация");
break;
}
case ImplicitFlowPageType.Consent:
{
_logger.LogDebug("Страница подтверждения доступа к скоупам");
break;
}
case ImplicitFlowPageType.Result:
{
return _vkAuthorization.GetAuthorizationResult(requestUrl);
}
}
var resultForm = await _authorizationFormsFactory.Create(pageType)
.ExecuteAsync(requestUrl, _authorizationParameters, token)
.ConfigureAwait(false);
return await NextStepAsync(resultForm, token)
.ConfigureAwait(false);
}
private static Uri GetRedirectUrl(Uri originalUrl)
{
var originalString = originalUrl.OriginalString;
var query = Url.ParseQueryString(originalString);
if (!query.TryGetValue("authorize_url", out var escapedUrl))
{
return originalUrl;
}
var unEscapedUrl = Uri.UnescapeDataString(escapedUrl);
return new(unEscapedUrl);
}
/// <summary>
/// Валидация параметров авторизации
/// </summary>
/// <exception cref="VkApiException"> Список неверно заданных параметров </exception>
private void ValidateAuthorizationParameters()
{
var errorsBuilder = new StringBuilder();
if (_authorizationParameters is null)
{
errorsBuilder.AppendLine("Параметры авторизации не установленны");
} else
{
if (_authorizationParameters.ApplicationId == 0)
{
errorsBuilder.AppendLine($"{nameof(_authorizationParameters.ApplicationId)} обязательный параметр");
}
if (string.IsNullOrWhiteSpace(_authorizationParameters.Login))
{
errorsBuilder.AppendLine($"{nameof(_authorizationParameters.Login)} обязательный параметр");
}
if (string.IsNullOrWhiteSpace(_authorizationParameters.Password))
{
errorsBuilder.AppendLine($"{nameof(_authorizationParameters.Password)} обязательный параметр");
}
}
var errors = errorsBuilder.ToString();
if (!string.IsNullOrWhiteSpace(errors))
{
throw new VkAuthorizationException(errors);
}
}
}