109 lines
4.2 KiB
C#
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);
|
|
}
|
|
} |