Files
YandexMusic/PlaylistShared/Controllers/AuthController.cs
2026-04-11 15:41:24 +03:00

109 lines
4.2 KiB
C#

using Microsoft.AspNetCore.Mvc;
using PlaylistShared.Models;
using System.Net.Http.Headers;
using System.Text.Json;
namespace PlaylistShared.Controllers;
[Microsoft.AspNetCore.Mvc.Route("auth")]
[ApiController]
public class AuthController : ControllerBase
{
private readonly IConfiguration _config;
private readonly HttpClient _httpClient;
private readonly AppDbContext _db;
private readonly SignInManager<ApplicationUser> _signInManager;
private readonly ILogger<AuthController> _logger;
public AuthController(
IConfiguration config,
IHttpClientFactory factory,
AppDbContext db,
SignInManager<ApplicationUser> signInManager,
ILogger<AuthController> logger)
{
_config = config;
_httpClient = factory.CreateClient();
_db = db;
_signInManager = signInManager;
_logger = logger;
}
[HttpGet("login")]
public IActionResult Login()
{
var clientId = _config["YandexOAuth:ClientId"];
var redirectUri = Url.Action(nameof(Callback), "Auth", null, Request.Scheme);
var authUrl = $"{_config["YandexOAuth:AuthorizationEndpoint"]}?response_type=code&client_id={clientId}&redirect_uri={Uri.EscapeDataString(redirectUri!)}";
return Redirect(authUrl);
}
[HttpGet("callback")]
public async Task<IActionResult> Callback(string code)
{
if (string.IsNullOrEmpty(code))
return BadRequest("Missing code");
var tokenResponse = await ExchangeCodeForTokenAsync(code);
if (tokenResponse is null)
return StatusCode(500, "Token exchange failed");
var userInfo = await GetUserInfoAsync(tokenResponse.AccessToken);
if (userInfo is null)
return StatusCode(500, "User info fetch failed");
var user = await _db.Users.FirstOrDefaultAsync(u => u.YandexId == userInfo.Id);
if (user is null)
{
user = new ApplicationUser
{
UserName = userInfo.Login,
YandexId = userInfo.Id,
Email = userInfo.DefaultEmail,
AccessToken = tokenResponse.AccessToken,
RefreshToken = tokenResponse.RefreshToken,
AccessTokenExpiresAt = DateTime.UtcNow.AddSeconds(tokenResponse.ExpiresIn)
};
_db.Users.Add(user);
}
else
{
user.AccessToken = tokenResponse.AccessToken;
user.RefreshToken = tokenResponse.RefreshToken;
user.AccessTokenExpiresAt = DateTime.UtcNow.AddSeconds(tokenResponse.ExpiresIn);
_db.Users.Update(user);
}
await _db.SaveChangesAsync();
await _signInManager.SignInAsync(user, isPersistent: false);
return Redirect("/");
}
private async Task<YandexTokenResponse?> ExchangeCodeForTokenAsync(string code)
{
var tokenUrl = _config["YandexOAuth:TokenEndpoint"];
var redirectUri = Url.Action(nameof(Callback), "Auth", null, Request.Scheme);
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("grant_type", "authorization_code"),
new KeyValuePair<string, string>("code", code),
new KeyValuePair<string, string>("client_id", _config["YandexOAuth:ClientId"]!),
new KeyValuePair<string, string>("client_secret", _config["YandexOAuth:ClientSecret"]!),
new KeyValuePair<string, string>("redirect_uri", redirectUri!)
});
var response = await _httpClient.PostAsync(tokenUrl!, content);
if (!response.IsSuccessStatusCode) return null;
var json = await response.Content.ReadAsStringAsync();
return JsonSerializer.Deserialize<YandexTokenResponse>(json);
}
private async Task<YandexUserInfo?> GetUserInfoAsync(string accessToken)
{
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("OAuth", accessToken);
var response = await _httpClient.GetAsync(_config["YandexOAuth:UserInfoEndpoint"]!);
if (!response.IsSuccessStatusCode) return null;
var json = await response.Content.ReadAsStringAsync();
return JsonSerializer.Deserialize<YandexUserInfo>(json);
}
}