diff --git a/Controllers/Managers/TokenManager.cs b/Controllers/Managers/TokenManager.cs index c00452f..4f819de 100644 --- a/Controllers/Managers/TokenManager.cs +++ b/Controllers/Managers/TokenManager.cs @@ -4,10 +4,14 @@ using System.Linq; using System.Security.Claims; using System.Security.Cryptography; using System.Threading.Tasks; +using System.IdentityModel.Tokens.Jwt; +using System.Security.Claims; +using System.Text; using JWT; using JWT.Serializers; using Microsoft.Extensions.Configuration; +using Microsoft.IdentityModel.Tokens; using Newtonsoft.Json; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Parameters; @@ -113,6 +117,40 @@ namespace Icarus.Controllers.Managers }; } + public LoginResult LoginSymmetric(User user) + { + var tokenResult = new TokenTierOne(); + tokenResult.TokenType = "Jwt"; + + var payload = Payload(); + var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["JWT:Secret"])); + var signIn = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); + var token = new JwtSecurityToken( + _config["JWT:Issuer"], + _config["JWT:Audience"], + payload, + expires: DateTime.UtcNow.AddMinutes(30), + signingCredentials: signIn); + + tokenResult.AccessToken = new JwtSecurityTokenHandler().WriteToken(token); + + var expClaim = payload.FirstOrDefault(cl => + { + return cl.Type.Equals("exp"); + }); + + var expiredDate = DateTime.Parse(expClaim.Value); + var exp = Math.Floor((expiredDate - DateTime.UnixEpoch).TotalSeconds); + tokenResult.Expiration = Convert.ToInt32(exp); + + return new LoginResult + { + UserID = user.UserID, Username = user.Username, Token = tokenResult.AccessToken, + TokenType = tokenResult.TokenType, Expiration = tokenResult.Expiration, + Message = "Successfully retrieved token" + }; + } + public bool IsTokenValid(string scope, string accessToken) { var result = false; @@ -201,23 +239,25 @@ namespace Icarus.Controllers.Managers private List Payload() { - const int expLimit = 24; + var expLimit = 30; var currentDate = DateTime.Now; - var expiredDate = currentDate.AddHours(expLimit); + var expiredDate = currentDate.AddMinutes(expLimit); var issued = Math.Floor((currentDate - DateTime.UnixEpoch).TotalSeconds); var expires = Math.Floor((expiredDate - DateTime.UnixEpoch).TotalSeconds); var issuer = "https://soaricarus.auth0.com"; issuer = "http://localhost:5002"; var audience = "https://icarus/api"; audience = "http://localhost:5002"; + var subject = _config["JWT:Subject"]; var claim = new List() { new System.Security.Claims.Claim("scope", AllScopes(), "string"), - new System.Security.Claims.Claim("exp", $"{expires}", "integer"), - new System.Security.Claims.Claim("aud", $"{audience}", "string"), - new System.Security.Claims.Claim("iss", $"{issuer}", "string"), - new System.Security.Claims.Claim("iat", $"{issued}", "integer") + new System.Security.Claims.Claim(JwtRegisteredClaimNames.Exp, expiredDate.ToString()), + new System.Security.Claims.Claim(JwtRegisteredClaimNames.Aud, audience), + new System.Security.Claims.Claim(JwtRegisteredClaimNames.Iss, issuer), + new Claim(JwtRegisteredClaimNames.Sub, subject), + new System.Security.Claims.Claim(JwtRegisteredClaimNames.Iat, currentDate.ToString()) }; return claim; diff --git a/Controllers/v1/AlbumController.cs b/Controllers/v1/AlbumController.cs index 903494a..7980f71 100644 --- a/Controllers/v1/AlbumController.cs +++ b/Controllers/v1/AlbumController.cs @@ -14,6 +14,7 @@ namespace Icarus.Controllers.V1 { [Route("api/v1/album")] [ApiController] + [Authorize] public class AlbumController : BaseController { #region Fields @@ -38,13 +39,8 @@ namespace Icarus.Controllers.V1 #region HTTP Routes [HttpGet] - public IActionResult Get() + public IActionResult GetAlbums() { - if (!IsTokenValid("read:albums")) - { - return StatusCode(401, "Not allowed"); - } - List albums = new List(); var albumContext = new AlbumContext(_connectionString); @@ -58,13 +54,8 @@ namespace Icarus.Controllers.V1 } [HttpGet("{id}")] - public IActionResult Get(int id) + public IActionResult GetAlbum(int id) { - if (!IsTokenValid("read:albums")) - { - return StatusCode(401, "Not allowed"); - } - Album album = new Album { AlbumID = id diff --git a/Controllers/v1/ArtistController.cs b/Controllers/v1/ArtistController.cs index 51e21b2..219e6c5 100644 --- a/Controllers/v1/ArtistController.cs +++ b/Controllers/v1/ArtistController.cs @@ -13,6 +13,7 @@ namespace Icarus.Controllers.V1 { [Route("api/v1/artist")] [ApiController] + [Authorize] public class ArtistController : BaseController { #region Fields @@ -37,13 +38,8 @@ namespace Icarus.Controllers.V1 #region HTTP Routes [HttpGet] - public IActionResult Get() + public IActionResult GetArtists() { - if (!IsTokenValid("read:artists")) - { - return StatusCode(401, "Not allowed"); - } - var artistContext = new ArtistContext(_connectionString); var artists = artistContext.Artists.ToList(); @@ -55,7 +51,7 @@ namespace Icarus.Controllers.V1 } [HttpGet("{id}")] - public IActionResult Get(int id) + public IActionResult GetArtist(int id) { if (!IsTokenValid("read:artists")) { diff --git a/Controllers/v1/BaseController.cs b/Controllers/v1/BaseController.cs index 911d273..9cec68a 100644 --- a/Controllers/v1/BaseController.cs +++ b/Controllers/v1/BaseController.cs @@ -17,6 +17,7 @@ namespace Icarus.Controllers.V1 #region Methods + [ApiExplorerSettings(IgnoreApi = true)] protected string ParseBearerTokenFromHeader() { var token = string.Empty; @@ -37,6 +38,7 @@ namespace Icarus.Controllers.V1 return token; } + [ApiExplorerSettings(IgnoreApi = true)] protected bool IsTokenValid(string scope) { var token = ParseBearerTokenFromHeader(); diff --git a/Controllers/v1/CoverArtController.cs b/Controllers/v1/CoverArtController.cs index 482b6a4..4d3ef29 100644 --- a/Controllers/v1/CoverArtController.cs +++ b/Controllers/v1/CoverArtController.cs @@ -15,6 +15,7 @@ namespace Icarus.Controllers.V1 { [Route("api/v1/coverart")] [ApiController] + [Authorize] public class CoverArtController : BaseController { #region Fields @@ -34,13 +35,9 @@ namespace Icarus.Controllers.V1 #region HTTP Routes - public IActionResult Get() + [HttpGet] + public IActionResult GetCoverArts() { - if (!IsTokenValid("read:songs")) - { - return StatusCode(401, "Not allowed"); - } - var coverArtContext = new CoverArtContext(_connectionString); var coverArtRecords = coverArtContext.CoverArtImages.ToList(); @@ -58,13 +55,8 @@ namespace Icarus.Controllers.V1 } [HttpGet("{id}")] - public async Task Get(int id) + public IActionResult GetCoverArt(int id) { - if (!IsTokenValid("download:cover_art")) - { - return StatusCode(401, "Not allowed"); - } - var coverArt = new CoverArt { CoverArtID = id }; var coverArtContext = new CoverArtContext(_connectionString); @@ -74,7 +66,7 @@ namespace Icarus.Controllers.V1 if (coverArt != null) { _logger.LogInformation("Found cover art record"); - var coverArtBytes = await System.IO.File.ReadAllBytesAsync( + var coverArtBytes = System.IO.File.ReadAllBytes( coverArt.ImagePath); return File(coverArtBytes, "application/x-msdownload", diff --git a/Controllers/v1/GenreController.cs b/Controllers/v1/GenreController.cs index 8e29502..d5a86c1 100644 --- a/Controllers/v1/GenreController.cs +++ b/Controllers/v1/GenreController.cs @@ -14,6 +14,7 @@ namespace Icarus.Controllers.V1 { [Route("api/v1/genre")] [ApiController] + [Authorize] public class GenreController : BaseController { #region Fields @@ -38,13 +39,8 @@ namespace Icarus.Controllers.V1 #region HTTP Routes [HttpGet] - public IActionResult Get() + public IActionResult GetGenres() { - if (!IsTokenValid("read:genre")) - { - return StatusCode(401, "Not allowed"); - } - var genres = new List(); var genreStore = new GenreContext(_connectionString); @@ -58,13 +54,8 @@ namespace Icarus.Controllers.V1 } [HttpGet("{id}")] - public IActionResult Get(int id) + public IActionResult GetGenre(int id) { - if (!IsTokenValid("read:genre")) - { - return StatusCode(401, "Not allowed"); - } - var genre = new Genre { GenreID = id diff --git a/Controllers/v1/LoginController.cs b/Controllers/v1/LoginController.cs index 78ee567..8446063 100644 --- a/Controllers/v1/LoginController.cs +++ b/Controllers/v1/LoginController.cs @@ -1,8 +1,5 @@ using System; -using System.Collections.Generic; -using System.Configuration; using System.Linq; -using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; @@ -41,7 +38,8 @@ namespace Icarus.Controllers.V1 #region HTTP endpoints - public IActionResult Post([FromBody] User user) + [HttpPost] + public IActionResult Login([FromBody] User user) { var context = new UserContext(_connectionString); @@ -55,34 +53,44 @@ namespace Icarus.Controllers.V1 Username = user.Username }; - if (context.Users.FirstOrDefault(usr => usr.Username.Equals(user.Username)) != null) + try { - user = context.Users.FirstOrDefault(usr => usr.Username.Equals(user.Username)); - - var validatePass = new PasswordEncryption(); - var validated = validatePass.VerifyPassword(user, password); - if (!validated) + if (context.Users.FirstOrDefault(usr => usr.Username.Equals(user.Username)) != null) { - loginRes.Message = message; - _logger.LogInformation(message); + user = context.Users.FirstOrDefault(usr => usr.Username.Equals(user.Username)); + + var validatePass = new PasswordEncryption(); + var validated = validatePass.VerifyPassword(user, password); + if (!validated) + { + loginRes.Message = message; + _logger.LogInformation(message); + + return Ok(loginRes); + } + + _logger.LogInformation("Successfully validated user credentials"); + + TokenManager tk = new TokenManager(_config); + + loginRes = tk.LoginSymmetric(user); return Ok(loginRes); } + else + { + loginRes.Message = message; - _logger.LogInformation("Successfully validated user credentials"); - - TokenManager tk = new TokenManager(_config); - - loginRes = tk.LogIn(user); - - return Ok(loginRes); + return NotFound(loginRes); + } } - else + catch (Exception ex) { - loginRes.Message = message; - - return NotFound(loginRes); + _logger.LogError("An error occurred: {0}", ex.Message); + _logger.LogError("Inner Exception: {0}", ex.InnerException.Message); } + + return NotFound(loginRes); } #endregion } diff --git a/Controllers/v1/RegisterController.cs b/Controllers/v1/RegisterController.cs index e1352d8..202b728 100644 --- a/Controllers/v1/RegisterController.cs +++ b/Controllers/v1/RegisterController.cs @@ -37,7 +37,7 @@ namespace Icarus.Controllers.V1 #endregion [HttpPost] - public IActionResult Post([FromBody] User user) + public IActionResult RegisterUser([FromBody] User user) { PasswordEncryption pe = new PasswordEncryption(); user.Password = pe.HashPassword(user); diff --git a/Controllers/v1/SongCompressedDataControllers.cs b/Controllers/v1/SongCompressedDataControllers.cs index cc96800..789a5d4 100644 --- a/Controllers/v1/SongCompressedDataControllers.cs +++ b/Controllers/v1/SongCompressedDataControllers.cs @@ -19,6 +19,7 @@ namespace Icarus.Controllers.V1 { [Route("api/v1/song/compressed/data")] [ApiController] + [Authorize] public class SongCompressedDataController : BaseController { #region Fields @@ -45,13 +46,8 @@ namespace Icarus.Controllers.V1 #region API Routes [HttpGet("{id}")] - public async Task Get(int id) + public async Task DownloadCompressedSong(int id) { - if (!IsTokenValid("download:songs")) - { - return StatusCode(401, "Not allowed"); - } - var context = new SongContext(_connectionString); SongCompression cmp = new SongCompression(_archiveDir); diff --git a/Controllers/v1/SongController.cs b/Controllers/v1/SongController.cs index d94f78f..c7ebe3d 100644 --- a/Controllers/v1/SongController.cs +++ b/Controllers/v1/SongController.cs @@ -18,6 +18,7 @@ namespace Icarus.Controllers.V1 { [Route("api/v1/song")] [ApiController] + [Authorize] public class SongController : BaseController { #region Fields @@ -47,13 +48,8 @@ namespace Icarus.Controllers.V1 [HttpGet] - public IActionResult Get() + public IActionResult GetSongs() { - if (!IsTokenValid("read:song_details")) - { - return StatusCode(401, "Not allowed"); - } - List songs = new List(); Console.WriteLine("Attemtping to retrieve songs"); _logger.LogInformation("Attempting to retrieve songs"); @@ -69,13 +65,8 @@ namespace Icarus.Controllers.V1 } [HttpGet("{id}")] - public IActionResult Get(int id) + public IActionResult GetSong(int id) { - if (!IsTokenValid("read:song_details")) - { - return StatusCode(401, "Not allowed"); - } - var context = new SongContext(_connectionString); Song song = new Song { SongID = id }; @@ -90,13 +81,8 @@ namespace Icarus.Controllers.V1 } [HttpPut("{id}")] - public IActionResult Put(int id, [FromBody] Song song) + public IActionResult UpdateSong(int id, [FromBody] Song song) { - if (!IsTokenValid("update:songs")) - { - return StatusCode(401, "Not allowed"); - } - var context = new SongContext(_connectionString); song.SongID = id; diff --git a/Controllers/v1/SongDataController.cs b/Controllers/v1/SongDataController.cs index 4760939..48341b6 100644 --- a/Controllers/v1/SongDataController.cs +++ b/Controllers/v1/SongDataController.cs @@ -20,6 +20,7 @@ namespace Icarus.Controllers.V1 { [Route("api/v1/song/data")] [ApiController] + [Authorize] public class SongDataController : BaseController { #region Fields @@ -47,18 +48,12 @@ namespace Icarus.Controllers.V1 [HttpGet("download/{id}")] - [Route("private-scoped")] - public async Task Get(int id) + public IActionResult Download(int id) { - if (!IsTokenValid("download:songs")) - { - return StatusCode(401, "Not allowed"); - } - var songContext = new SongContext(_connectionString); var songMetaData = songContext.RetrieveRecord(new Song { SongID = id}); - var song = await _songMgr.RetrieveSong(songMetaData); + var song = _songMgr.RetrieveSong(songMetaData).Result; return File(song.Data, "application/x-msdownload", songMetaData.Filename); } @@ -76,14 +71,8 @@ namespace Icarus.Controllers.V1 // Cover art // [HttpPost("upload"), DisableRequestSizeLimit] - [Route("private-scoped")] - public IActionResult Post([FromForm(Name = "file")] List songData) + public IActionResult Upload([FromForm(Name = "file")] List songData) { - if (!IsTokenValid("upload:songs")) - { - return StatusCode(401, "Not allowed"); - } - try { // Console.WriteLine("Uploading song..."); @@ -118,14 +107,8 @@ namespace Icarus.Controllers.V1 // as well as the cover art // [HttpPost("upload/with/data")] - [Route("private-scoped")] - public IActionResult Post ([FromForm] UploadSongWithDataForm up) + public IActionResult UploadWithData([FromForm] UploadSongWithDataForm up) { - if (!IsTokenValid("upload:songs")) - { - return StatusCode(401, "Not allowed"); - } - try { if (up.SongData.Length > 0 && up.CoverArtData.Length > 0 && !string.IsNullOrEmpty(up.SongFile)) @@ -145,13 +128,8 @@ namespace Icarus.Controllers.V1 } [HttpDelete("delete/{id}")] - public IActionResult Delete(int id) + public IActionResult DeleteSong(int id) { - if (!IsTokenValid("delete:songs")) - { - return StatusCode(401, "Not allowed"); - } - var songContext = new SongContext(_connectionString); var songMetaData = new Song{ SongID = id }; @@ -175,15 +153,15 @@ namespace Icarus.Controllers.V1 } - public class UploadSongWithDataForm - { - [FromForm(Name = "file")] - public IFormFile SongData { get; set; } - // TODO: Think about making this optional and if it is not provided, use the stock cover art - [FromForm(Name = "cover")] - public IFormFile CoverArtData { get; set; } - [FromForm(Name = "metadata")] - public string SongFile { get; set; } - } + public class UploadSongWithDataForm + { + [FromForm(Name = "file")] + public IFormFile SongData { get; set; } + // NOTE: Think about making this optional and if it is not provided, use the stock cover art + [FromForm(Name = "cover")] + public IFormFile CoverArtData { get; set; } + [FromForm(Name = "metadata")] + public string SongFile { get; set; } + } } } diff --git a/Controllers/v1/SongStreamController.cs b/Controllers/v1/SongStreamController.cs index b273a08..de92076 100644 --- a/Controllers/v1/SongStreamController.cs +++ b/Controllers/v1/SongStreamController.cs @@ -20,6 +20,7 @@ namespace Icarus.Controllers.V1 { [Route("api/v1/song/stream")] [ApiController] + [Authorize] public class SongStreamController : BaseController { #region Fields @@ -44,13 +45,8 @@ namespace Icarus.Controllers.V1 #region HTTP endpoints [HttpGet("{id}")] - public async Task Get(int id) + public async Task StreamSong(int id) { - if (!IsTokenValid("stream:songs")) - { - return StatusCode(401, "Not allowed"); - } - var context = new SongContext(_config.GetConnectionString("DefaultConnection")); var song = context.Songs.FirstOrDefault(sng => sng.SongID == id); diff --git a/Icarus.csproj b/Icarus.csproj index 628bbcb..7e626cd 100644 --- a/Icarus.csproj +++ b/Icarus.csproj @@ -25,6 +25,7 @@ + diff --git a/Properties/launchSettings.json b/Properties/launchSettings.json index 82a1227..b71d9cb 100644 --- a/Properties/launchSettings.json +++ b/Properties/launchSettings.json @@ -12,7 +12,7 @@ "IIS Express": { "commandName": "IISExpress", "launchBrowser": true, - "launchUrl": "api/values", + "launchUrl": "swagger", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } @@ -20,7 +20,8 @@ "Icarus": { "commandName": "Project", "launchBrowser": true, - "launchUrl": "api/values", + "dotnetRuneMessage": true, + "launchUrl": "swagger", "applicationUrl": "http://localhost:5002", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" diff --git a/README.md b/README.md index e24d59e..c3bb084 100644 --- a/README.md +++ b/README.md @@ -37,32 +37,29 @@ One can interface with Icarus the music server either by: ## Getting started There are several things that need to be completed to properly setup and secure the API. -1. Creating RSA keys +This API uses OpenAPI Specification 3.0. After configuring the API, launch the software +and navigate your browser to https://localhost:5001/swagger to view the endpoints. + +1. JWT Information 2. API filesystem paths 3. Database connection string 4. Migrations -### Creating RSA keys +### JWT Information -1. Create private key -``` -openssl genrsa -out private.pem 2048 -``` -2. Create public key -``` -openssl rsa -in private -pubout -out public.pem -``` - -Configure the key paths in the config files +Configure JWT information. Notably the Secret ```Json -"RSAKeys": { - "PrivateKeyPath": "", - "PublicKeyPath": "" -} + "JWT": { + "Issuer": "IcarusAPI", + "Audience": "IcarusAPIClient", + "Secret": "Manaiswhatyouthinkitis", + "Subject": "Authorization" + }, ``` + Replace [domain] with the domain name that represent's your domain. Replace [identifier] with the identifer root name in the appsettings environment file. Not the friendly name but the root name of the identifier, omitting the http protocol and the *api* path. ```Json @@ -72,6 +69,9 @@ Replace [domain] with the domain name that represent's your domain. Replace [ide }, ``` +**Note**: The Auth0 section is likely to be changed or removed in future releases. + + ### API filesystem paths For the purposes of properly uploading, downloading, updating, deleting, and streaming songs the API filesystem paths must be configured. What is meant by this is that the `RootMusicPath` directory where all music will be stored must exist as well as the `ArchivePath` and `TemporaryMusicPath` paths. An example on a Linux system: @@ -140,11 +140,6 @@ From this point the database has been successfully configured. Metadata and song Please read [CONTRIBUTING.md](CONTRIBUTING.md) for details on the code of conduct, and the process for submitting pull requests to the project. -## Authors - -* [kdeng00](https://github.com/kdeng00) - -See also the list of [contributors](https://github.com/amazing-username/Icarus/graphs/contributors) who participated in this project. ## License diff --git a/Startup.cs b/Startup.cs index 6dea1e4..89c50d1 100644 --- a/Startup.cs +++ b/Startup.cs @@ -1,13 +1,18 @@ using System; +using System.Text; +using System.Linq; +using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Microsoft.EntityFrameworkCore; using Microsoft.IdentityModel.Tokens; +using Microsoft.OpenApi.Models; using Newtonsoft.Json; using NLog; using NLog.Web; @@ -17,35 +22,6 @@ using Icarus.Database.Contexts; namespace Icarus { - public static class ServiceStartup - { - public static IServiceCollection AddAsymmetricAuthentication(this IServiceCollection services, IConfiguration configuration) - { - var issuerSigningCertificate = new Icarus.Certs.SigningIssuerCertificate(); - RsaSecurityKey issuerSigningKey = issuerSigningCertificate.GetIssuerSigningKey(configuration["RSAKeys:PublicKeyPath"]); - - services.AddAuthentication(authOptions => - { - }) - .AddJwtBearer(options => - { - options.TokenValidationParameters = new TokenValidationParameters - { - IssuerSigningKey = issuerSigningKey, - }; - }); - - return services; - } - - private static bool LifetimeValidator(DateTime? notBefore, - DateTime? expires, - SecurityToken securityToken, - TokenValidationParameters validationParameters) - { - return expires != null && expires > DateTime.UtcNow; - } - } public class Startup { #region Constructors @@ -72,6 +48,20 @@ namespace Icarus var connString = Configuration.GetConnectionString("DefaultConnection"); + services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options => + { + options.RequireHttpsMetadata = false; + options.SaveToken = true; + options.TokenValidationParameters = new TokenValidationParameters() + { + ValidateIssuer = true, + ValidateAudience = true, + ValidAudience = Configuration["JWT:Audience"], + ValidIssuer = Configuration["JWT:Issuer"], + IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["JWT:Secret"])) + }; + }); + services.AddDbContext(options => options.UseMySQL(connString)); services.AddDbContext(options => options.UseMySQL(connString)); services.AddDbContext(options => options.UseMySQL(connString)); @@ -79,24 +69,50 @@ namespace Icarus services.AddDbContext(options => options.UseMySQL(connString)); services.AddDbContext(options => options.UseMySQL(connString)); - services.AddAsymmetricAuthentication(Configuration); - - /** - services.AddTransient(au => new AuthenticationService(new UserService(Configuration), new TokenService(Configuration), Configuration)); - services.AddTransient(us => new UserService(Configuration)); - services.AddTransient(tk => new TokenService(Configuration)); - services.AddTransient(); - services.AddTransient(uc => new UserContext(connString)); - */ - services.AddControllers() .AddNewtonsoftJson(); + + services.AddEndpointsApiExplorer(); + services.AddSwaggerGen(c => + { + c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First()); + + c.SwaggerDoc("v1", new OpenApiInfo { Title = "Icarus", Version = "v1" }); + c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme() + { + Name = "Authorization", + Scheme = "Bearer", + BearerFormat = "JWT", + Type = SecuritySchemeType.ApiKey, + In = ParameterLocation.Header, + Description = "Bearer *Auth Token*", + }); + c.AddSecurityRequirement(new OpenApiSecurityRequirement + { + { + new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { + Type = ReferenceType.SecurityScheme, + Id = "Bearer" + } + }, + new string[] {} + } + }); + }); } // Called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { // NOTE: Dev-related configuration can be done when env.IsDevelopment() evaluated to true + if (env.IsDevelopment()) + { + app.UseSwagger(); + app.UseSwaggerUI(); + } app.UseRouting(); app.UseAuthentication(); diff --git a/appsettings.Development.json b/appsettings.Development.json index cd727fb..c8ed0de 100644 --- a/appsettings.Development.json +++ b/appsettings.Development.json @@ -16,6 +16,12 @@ "PrivateKeyPath": "", "PublicKeyPath": "" }, + "JWT": { + "Issuer": "", + "Audience": "", + "Secret": "", + "Subject": "" + }, "ConnectionStrings": { "DefaultConnection": "Server=;Database=;Uid=;Pwd=;" }, diff --git a/appsettings.json b/appsettings.json index 68eb482..71f2123 100644 --- a/appsettings.json +++ b/appsettings.json @@ -16,6 +16,12 @@ "PrivateKeyPath": "", "PublicKeyPath": "" }, + "JWT": { + "Issuer": "", + "Audience": "", + "Secret": "", + "Subject": "" + }, "ConnectionStrings": { "DefaultConnection": "Server=;Database=;Uid=;Pwd=;" },