using System.IdentityModel.Tokens.Jwt; using System.Text; using System.Text.Json; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Microsoft.IdentityModel.Tokens; using MoonCore.Exceptions; using MoonCore.Extended.Abstractions; using MoonCore.Helpers; using Moonlight.ApiServer.Configuration; using Moonlight.ApiServer.Database.Entities; using Moonlight.ApiServer.Interfaces; using Moonlight.Shared.Http.Requests.Auth; using Moonlight.Shared.Http.Responses.Auth; using Moonlight.Shared.Http.Responses.OAuth2; namespace Moonlight.ApiServer.Http.Controllers.Auth; [ApiController] [Route("api/auth")] public class AuthController : Controller { private readonly AppConfiguration Configuration; private readonly ILogger Logger; private readonly DatabaseRepository UserRepository; private readonly IOAuth2Provider OAuth2Provider; private readonly string RedirectUri; private readonly string EndpointUri; public AuthController( AppConfiguration configuration, ILogger logger, DatabaseRepository userRepository, IOAuth2Provider oAuth2Provider ) { UserRepository = userRepository; OAuth2Provider = oAuth2Provider; Configuration = configuration; Logger = logger; RedirectUri = string.IsNullOrEmpty(Configuration.Authentication.OAuth2.AuthorizationRedirect) ? Configuration.PublicUrl : Configuration.Authentication.OAuth2.AuthorizationRedirect; EndpointUri = string.IsNullOrEmpty(Configuration.Authentication.OAuth2.AuthorizationEndpoint) ? Configuration.PublicUrl + "/oauth2/authorize" : Configuration.Authentication.OAuth2.AuthorizationEndpoint; } [AllowAnonymous] [HttpGet("start")] public Task Start() { var response = new LoginStartResponse() { ClientId = Configuration.Authentication.OAuth2.ClientId, RedirectUri = RedirectUri, Endpoint = EndpointUri }; return Task.FromResult(response); } [AllowAnonymous] [HttpPost("complete")] public async Task Complete([FromBody] LoginCompleteRequest request) { var user = await OAuth2Provider.Sync(request.Code); if (user == null) throw new HttpApiException("Unable to load user data", 500); // Generate token var securityTokenDescriptor = new SecurityTokenDescriptor() { Expires = DateTime.Now.AddYears(Configuration.Authentication.TokenDuration), IssuedAt = DateTime.Now, NotBefore = DateTime.Now.AddMinutes(-1), Claims = new Dictionary() { { "userId", user.Id }, { "permissions", string.Join(";", user.Permissions) } }, SigningCredentials = new SigningCredentials( new SymmetricSecurityKey( Encoding.UTF8.GetBytes(Configuration.Authentication.Secret) ), SecurityAlgorithms.HmacSha256 ), Issuer = Configuration.PublicUrl, Audience = Configuration.PublicUrl }; var jwtSecurityTokenHandler = new JwtSecurityTokenHandler(); var securityToken = jwtSecurityTokenHandler.CreateToken(securityTokenDescriptor); var jwt = jwtSecurityTokenHandler.WriteToken(securityToken); return new() { AccessToken = jwt }; } [Authorize] [HttpGet("check")] public async Task Check() { var userIdClaim = User.Claims.First(x => x.Type == "userId"); var userId = int.Parse(userIdClaim.Value); var user = await UserRepository.Get().FirstAsync(x => x.Id == userId); return new() { Email = user.Email, Username = user.Username, Permissions = user.Permissions }; } }