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 _signInManager; private readonly ILogger _logger; public AuthController( IConfiguration config, IHttpClientFactory factory, AppDbContext db, SignInManager signInManager, ILogger 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 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 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("grant_type", "authorization_code"), new KeyValuePair("code", code), new KeyValuePair("client_id", _config["YandexOAuth:ClientId"]!), new KeyValuePair("client_secret", _config["YandexOAuth:ClientSecret"]!), new KeyValuePair("redirect_uri", redirectUri!) }); var response = await _httpClient.PostAsync(tokenUrl!, content); if (!response.IsSuccessStatusCode) return null; var json = await response.Content.ReadAsStringAsync(); return JsonSerializer.Deserialize(json); } private async Task 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(json); } }