Доработана QR авторизация

This commit is contained in:
FrigaT
2026-04-20 16:06:47 +03:00
parent 12241639dc
commit 9c95e6b189
11 changed files with 784 additions and 45 deletions

View File

@@ -2,7 +2,6 @@
using PlaylistShared.Api.Entities;
using System.Net;
using YandexMusic;
using YandexMusic.API.Common;
namespace PlaylistShared.Api.Services;
@@ -12,7 +11,6 @@ namespace PlaylistShared.Api.Services;
public class YandexApiService : IDisposable
{
private readonly IDataProtector _dataProtector;
private readonly HttpClient _httpClient;
private readonly YandexMusicClient _client;
private readonly CookieContainer _cookieContainer;
@@ -33,12 +31,7 @@ public class YandexApiService : IDisposable
{
_dataProtector = provider.CreateProtector("YandexTokens");
_cookieContainer = new();
_httpClient = YandexMusicHttpClientFactory.CreateDefault(
cookieContainer: _cookieContainer,
proxy: proxy,
timeout: timeout
);
_client = new YandexMusicClient(_httpClient);
_client = new YandexMusicClient(_cookieContainer, proxy, timeout);
}
@@ -107,21 +100,6 @@ public class YandexApiService : IDisposable
return cookie?.Value;
}
private void UpdateHttpClientCookieContainer(CookieContainer container)
{
var handler = GetInnerHandler(_httpClient);
if (handler is HttpClientHandler httpHandler)
httpHandler.CookieContainer = container;
}
private static HttpMessageHandler GetInnerHandler(HttpClient client)
{
var field = client.GetType().GetField("_handler", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
if (field?.GetValue(client) is HttpMessageHandler handler)
return handler;
return new HttpClientHandler();
}
/// <summary>
/// Авторизуется с помощью OAuth-токена.
/// </summary>
@@ -133,6 +111,5 @@ public class YandexApiService : IDisposable
public void Dispose()
{
_client.Dispose();
_httpClient.Dispose();
}
}

View File

@@ -1,9 +1,9 @@
using PlaylistShared.Api.Data;
using Microsoft.EntityFrameworkCore;
using PlaylistShared.Api.Data;
using PlaylistShared.Api.Entities;
using PlaylistShared.Shared.Yandex;
using System.Net;
using System.Text.Json;
using YandexMusic.API.Models.Account;
namespace PlaylistShared.Api.Services;
@@ -20,12 +20,33 @@ public class YandexAuthService
_dbContext = dbContext;
}
internal async Task<YandexAuthQr> GetQrOrGenerate(ApplicationUser user)
{
var existingSession = _dbContext.YandexAuthSessions
.Where(s => s.UserId == user.Id && !s.IsConfirmed && s.CreatedAt > DateTime.UtcNow.AddMinutes(-5))
.OrderByDescending(s => s.CreatedAt)
.FirstOrDefault();
if (existingSession != null)
{
return new YandexAuthQr
{
QrLink = existingSession.QrCodeUrl,
SessionId = existingSession.Id.ToString()
};
}
return await GenerateQrAsync(user);
}
internal async Task<YandexAuthQr> GenerateQrAsync(ApplicationUser user)
{
var client = _apiService.Client;
var qr = await client.GetAuthQRLink();
var trackId = client.AuthStorage.AuthToken.TrackId;
var csfrToken = client.AuthStorage.AuthToken.CsfrToken;
var headerProcessUuid = client.AuthStorage.HeaderToken.ProcessUuid;
var headerCsfrToken = client.AuthStorage.HeaderToken.CsfrToken;
if (string.IsNullOrEmpty(qr))
throw new Exception("Не удалось получить QR-ссылку");
@@ -41,6 +62,8 @@ public class YandexAuthService
IsConfirmed = false,
TrackId = trackId,
CsfrToken = csfrToken,
HeaderCsfrToken = headerCsfrToken,
HeaderProcessId = headerProcessUuid,
};
@@ -67,19 +90,26 @@ public class YandexAuthService
_apiService.Client.AuthStorage.AuthToken.CsfrToken = session?.CsfrToken ?? "";
_apiService.Client.AuthStorage.AuthToken.TrackId = session?.TrackId ?? "";
_apiService.Client.AuthStorage.HeaderToken.CsfrToken = session?.HeaderCsfrToken ?? "";
_apiService.Client.AuthStorage.HeaderToken.ProcessUuid = session?.HeaderProcessId ?? "";
var status = await _apiService.Client.AuthorizeByQR();
var status = await _apiService.Client.CheckQRStatusAsync();
if (status?.Status == YAuthStatus.Ok)
if (status?.State == "otp_auth_finished")
{
session.ConfirmedAt = DateTime.UtcNow;
session.IsConfirmed = true;
await _dbContext.SaveChangesAsync();
return new()
try
{
Status = Shared.Enums.YandexAuthQrStatus.Authorized,
};
var auth = await _apiService.Client.AuthorizeByQR();
}
catch (Exception ex)
{
return new() { Status = Shared.Enums.YandexAuthQrStatus.Error, };
}
_dbContext.YandexAuthSessions.Where(t => t.UserId == session.UserId).ExecuteDelete();
_dbContext.SaveChanges();
return new() { Status = Shared.Enums.YandexAuthQrStatus.Authorized, };
}
return new()
@@ -91,7 +121,6 @@ public class YandexAuthService
private string SerializeCookies(CookieContainer container)
{
var domains = new[] { "yandex.ru", "passport.yandex.ru", ".yandex.ru" };
var allCookies = new List<object>();
var cookies = container.GetAllCookies();
@@ -108,8 +137,7 @@ public class YandexAuthService
var cookies = JsonSerializer.Deserialize<List<CookieData>>(serializedCookies);
foreach (var c in cookies)
{
var uri = new Uri($"{c.Domain}");
container.Add(uri, new Cookie(c.Name, c.Value, c.Path, c.Domain));
container.Add(new Cookie(c.Name, c.Value, c.Path, c.Domain));
}
}