Adding authentication and authorization flow
This commit is contained in:
@@ -21,6 +21,21 @@
|
||||
"Name": "MIT License",
|
||||
"Url": "https://github.com/csimonapastore/BasicDotnetTemplate/blob/main/LICENSE.md"
|
||||
}
|
||||
},
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"JWTSettings": {
|
||||
"ValidAudience": "http://localhost:4200",
|
||||
"ValidIssuer": "http://localhost:5000",
|
||||
"Secret": "JWTAuthenticationHIGHsecuredPasswordVVVp1OH7Xzyr",
|
||||
"ExpiredAfterMinsOfInactivity": 15
|
||||
},
|
||||
"EncryptionSettings": {
|
||||
"Salt": "S7VIidfXQf1tOQYX"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
42
MainProject.Tests/JsonData/invalidCryptAppsettings.json
Normal file
42
MainProject.Tests/JsonData/invalidCryptAppsettings.json
Normal file
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"AppSettings" :
|
||||
{
|
||||
"Settings": {
|
||||
"Name": "MainProject",
|
||||
"Version": "v1.0",
|
||||
"Description": "This template contains basic configuration for a .Net 8 backend"
|
||||
},
|
||||
"DatabaseSettings": {
|
||||
"SqlServerConnectionString": "SQLSERVER_DB_SERVER",
|
||||
"MongoDbConnectionString": "MONGO_DB_SERVER",
|
||||
"PostgreSQLConnectionString": "POSTGRESQL_DB_SERVER"
|
||||
},
|
||||
"OpenApiSettings": {
|
||||
"TermsOfServiceUrl": "",
|
||||
"OpenApiContact": {
|
||||
"Name": "",
|
||||
"Url": ""
|
||||
},
|
||||
"OpenApiLicense": {
|
||||
"Name": "MIT License",
|
||||
"Url": "https://github.com/csimonapastore/BasicDotnetTemplate/blob/main/LICENSE.md"
|
||||
}
|
||||
},
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"JWTSettings": {
|
||||
"ValidAudience": "http://localhost:4200",
|
||||
"ValidIssuer": "http://localhost:5000",
|
||||
"Secret": "JWTAuthenticationHIGHsecuredPasswordVVVp1OH7Xzyr",
|
||||
"ExpiredAfterMinsOfInactivity": 15
|
||||
},
|
||||
"EncryptionSettings": {
|
||||
"Salt": "AAAAA"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
108
MainProject.Tests/Utils/CryptoUtils_Tests.cs
Normal file
108
MainProject.Tests/Utils/CryptoUtils_Tests.cs
Normal file
@@ -0,0 +1,108 @@
|
||||
using System;
|
||||
using BasicDotnetTemplate.MainProject.Models.Settings;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using BasicDotnetTemplate.MainProject.Utils;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
|
||||
namespace BasicDotnetTemplate.MainProject.Tests;
|
||||
|
||||
[TestClass]
|
||||
public class CryptoUtils_Tests
|
||||
{
|
||||
[TestMethod]
|
||||
public void Decrypt_Success()
|
||||
{
|
||||
try
|
||||
{
|
||||
string encryptedData = "d2ejdI1f4GYpq2kTB1nmeQkZXqR3QSxH8Yqkl7iv7zgfQ13qG/0dUUsreG/WGHWRBE5mVWaV43A=";
|
||||
WebApplicationBuilder builder = WebApplication.CreateBuilder(Array.Empty<string>());
|
||||
AppSettings appSettings = ProgramUtils.AddConfiguration(ref builder, System.AppDomain.CurrentDomain.BaseDirectory + "/JsonData");
|
||||
CryptUtils cryptoUtils = new CryptUtils(appSettings);
|
||||
var decryptedData = cryptoUtils.Decrypt(encryptedData);
|
||||
var isEqual = decryptedData == "ThisIsASuccessfullTest";
|
||||
Assert.IsTrue(isEqual);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex.InnerException);
|
||||
Assert.Fail($"An exception was thrown: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Decrypt_Error()
|
||||
{
|
||||
try
|
||||
{
|
||||
string encryptedData = "d1ejdI1f4GYpq2kTB1nmeQkZXqR3QSxH8Yqkl7iv7zgfQ13qG/0dUUsreG/WGHWRBE5mVWaV43A=";
|
||||
WebApplicationBuilder builder = WebApplication.CreateBuilder(Array.Empty<string>());
|
||||
AppSettings appSettings = ProgramUtils.AddConfiguration(ref builder, System.AppDomain.CurrentDomain.BaseDirectory + "/JsonData");
|
||||
CryptUtils cryptoUtils = new CryptUtils(appSettings);
|
||||
var decryptedData = cryptoUtils.Decrypt(encryptedData);
|
||||
var isEqual = decryptedData == "ThisIsASuccessfullTest";
|
||||
Assert.IsFalse(isEqual);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex.InnerException);
|
||||
Assert.Fail($"An exception was thrown: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Decrypt_ArgumentException()
|
||||
{
|
||||
try
|
||||
{
|
||||
string encryptedData = "d1ejdI1f4GYpq2kTB1nmeQkZXqR3QSxH8Yqkl7iv7zgfQ13qG/0dUUsreG/WGHWRBE5mVWaV43A=";
|
||||
WebApplicationBuilder builder = WebApplication.CreateBuilder(Array.Empty<string>());
|
||||
AppSettings appSettings = ProgramUtils.AddConfiguration(ref builder, System.AppDomain.CurrentDomain.BaseDirectory + "/JsonData", "invalidCryptAppsettings.json");
|
||||
CryptUtils cryptoUtils = new CryptUtils(appSettings);
|
||||
try
|
||||
{
|
||||
var decryptedData = cryptoUtils.Decrypt(encryptedData);
|
||||
Assert.Fail($"Expected exception instead of response: {decryptedData}");
|
||||
}
|
||||
catch (ArgumentException argumentException)
|
||||
{
|
||||
Assert.IsInstanceOfType(argumentException, typeof(ArgumentException));
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Assert.IsInstanceOfType(exception, typeof(ArgumentException));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex.InnerException);
|
||||
Assert.Fail($"An exception was thrown: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Decrypt_Empty()
|
||||
{
|
||||
try
|
||||
{
|
||||
string encryptedData = "WGHWRBE5mVWaV=";
|
||||
WebApplicationBuilder builder = WebApplication.CreateBuilder(Array.Empty<string>());
|
||||
AppSettings appSettings = ProgramUtils.AddConfiguration(ref builder, System.AppDomain.CurrentDomain.BaseDirectory + "/JsonData");
|
||||
CryptUtils cryptoUtils = new CryptUtils(appSettings);
|
||||
var decryptedData = cryptoUtils.Decrypt(encryptedData);
|
||||
var isEqual = decryptedData == String.Empty;
|
||||
Assert.IsTrue(isEqual);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex.InnerException);
|
||||
Assert.Fail($"An exception was thrown: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,11 +1,3 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using BasicDotnetTemplate.MainProject;
|
||||
using BasicDotnetTemplate.MainProject.Models.Api.Response;
|
||||
using Microsoft.Extensions.DependencyModel.Resolution;
|
||||
using BasicDotnetTemplate.MainProject.Models.Settings;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using BasicDotnetTemplate.MainProject.Utils;
|
||||
|
||||
62
MainProject/Controllers/AuthController.cs
Normal file
62
MainProject/Controllers/AuthController.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using BasicDotnetTemplate.MainProject.Core.Attributes;
|
||||
using BasicDotnetTemplate.MainProject.Models.Api.Request.Auth;
|
||||
using BasicDotnetTemplate.MainProject.Models.Api.Response;
|
||||
using BasicDotnetTemplate.MainProject.Services;
|
||||
|
||||
namespace BasicDotnetTemplate.MainProject.Controllers
|
||||
{
|
||||
[Route("[controller]")]
|
||||
public class AuthController : BaseController
|
||||
{
|
||||
private IAuthService _authService;
|
||||
public AuthController(
|
||||
IConfiguration configuration,
|
||||
IAuthService authService
|
||||
) : base(configuration)
|
||||
{
|
||||
this._authService = authService;
|
||||
}
|
||||
|
||||
[HttpPost("authenticate")]
|
||||
[ProducesResponseType<string>(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType<BaseResponse>(StatusCodes.Status404NotFound)]
|
||||
[ProducesResponseType<BaseResponse>(StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType<BaseResponse>(StatusCodes.Status500InternalServerError)]
|
||||
public async Task<IActionResult> AuthenticateAsync([FromBody] AuthenticateRequest request)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (
|
||||
request == null ||
|
||||
request.Data == null ||
|
||||
String.IsNullOrEmpty(request.Data.Username) ||
|
||||
String.IsNullOrEmpty(request.Data.Password)
|
||||
)
|
||||
{
|
||||
return BadRequest("Request is not well formed");
|
||||
}
|
||||
var data = await this._authService.AuthenticateAsync(request.Data);
|
||||
|
||||
if (data == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
return Success(String.Empty, data);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
var message = "Something went wrong";
|
||||
if (!String.IsNullOrEmpty(exception?.Message))
|
||||
{
|
||||
message += $". {exception?.Message}";
|
||||
}
|
||||
return InternalServerError(message);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,6 +37,12 @@ namespace BasicDotnetTemplate.MainProject.Controllers
|
||||
return StatusCode((int)HttpStatusCode.OK, CreateResponse(HttpStatusCode.OK, message, data));
|
||||
}
|
||||
|
||||
protected IActionResult NotModified(string message, object? data = null)
|
||||
{
|
||||
message = String.IsNullOrEmpty(message) ? "Not modified" : message;
|
||||
return StatusCode((int)HttpStatusCode.NotModified, CreateResponse(HttpStatusCode.NotModified, message, data));
|
||||
}
|
||||
|
||||
protected IActionResult NotFound(string message, object? data = null)
|
||||
{
|
||||
message = String.IsNullOrEmpty(message) ? "Not found" : message;
|
||||
|
||||
32
MainProject/Core/Attributes/JwtAuthorizationAttribute .cs
Normal file
32
MainProject/Core/Attributes/JwtAuthorizationAttribute .cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using System;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
namespace BasicDotnetTemplate.MainProject.Core.Attributes
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
|
||||
public class JwtAuthorizationAttribute : Attribute, IAuthorizationFilter
|
||||
{
|
||||
private readonly string? _policyName;
|
||||
|
||||
public JwtAuthorizationAttribute() { }
|
||||
public JwtAuthorizationAttribute(string policyName)
|
||||
{
|
||||
_policyName = policyName;
|
||||
}
|
||||
|
||||
public void OnAuthorization(AuthorizationFilterContext context)
|
||||
{
|
||||
return;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<Configuration>Debug</Configuration>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
@@ -13,18 +14,22 @@
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.AspNetCore" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Abstractions" Version="9.0.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.8">
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.13" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.13" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Abstractions" Version="9.0.2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.2">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.8" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.8">
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="9.0.2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.2">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Identity.Web" Version="3.7.1" />
|
||||
<PackageReference Include="MongoDB.Driver" Version="2.28.0" />
|
||||
<PackageReference Include="MongoDB.EntityFrameworkCore" Version="8.1.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
|
||||
9
MainProject/Models/Api/Common/Role/UserRole.cs
Normal file
9
MainProject/Models/Api/Common/Role/UserRole.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace BasicDotnetTemplate.MainProject.Models.Api.Common.Role;
|
||||
|
||||
public class UserRole
|
||||
{
|
||||
#nullable enable
|
||||
public string? Guid { get; set; }
|
||||
public string? Name { get; set; }
|
||||
#nullable disable
|
||||
}
|
||||
19
MainProject/Models/Api/Common/User/AuthenticatedUser.cs
Normal file
19
MainProject/Models/Api/Common/User/AuthenticatedUser.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using BasicDotnetTemplate.MainProject.Models.Api.Common.Role;
|
||||
|
||||
namespace BasicDotnetTemplate.MainProject.Models.Api.Common.User;
|
||||
|
||||
public class AuthenticatedUser
|
||||
{
|
||||
#nullable enable
|
||||
public string? Guid { get; set; }
|
||||
public string? Username { get; set; }
|
||||
public string? FirstName { get; set; }
|
||||
public string? LastName { get; set; }
|
||||
public string? Email { get; set; }
|
||||
public UserRole? Role { get; set; }
|
||||
#nullable disable
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
13
MainProject/Models/Api/Data/Auth/AuthenticateRequestData.cs
Normal file
13
MainProject/Models/Api/Data/Auth/AuthenticateRequestData.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace BasicDotnetTemplate.MainProject.Models.Api.Data.Auth;
|
||||
|
||||
public class AuthenticateRequestData
|
||||
{
|
||||
#nullable enable
|
||||
public string? Username { get; set; }
|
||||
public string? Password { get; set; }
|
||||
#nullable disable
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
14
MainProject/Models/Api/Request/Auth/AuthenticateRequest.cs
Normal file
14
MainProject/Models/Api/Request/Auth/AuthenticateRequest.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using BasicDotnetTemplate.MainProject.Models.Api.Data.Auth;
|
||||
|
||||
namespace BasicDotnetTemplate.MainProject.Models.Api.Request.Auth;
|
||||
|
||||
public class AuthenticateRequest
|
||||
{
|
||||
#nullable enable
|
||||
public AuthenticateRequestData? Data { get; set; }
|
||||
#nullable disable
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ namespace BasicDotnetTemplate.MainProject.Models.Database.SqlServer
|
||||
public class Base
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Guid { get; set; }
|
||||
public DateTime CreationTime { get; set; }
|
||||
public int CreationUserId { get; set; }
|
||||
public DateTime UpdateTime { get; set; }
|
||||
|
||||
@@ -7,6 +7,8 @@ public class AppSettings
|
||||
public PrivateSettings? PrivateSettings { get; set; }
|
||||
public OpenApiSettings? OpenApiSettings { get; set; }
|
||||
public DatabaseSettings? DatabaseSettings { get; set; }
|
||||
public JWTSettings? JWTSettings { get; set; }
|
||||
public EncryptionSettings? EncryptionSettings { get; set; }
|
||||
|
||||
#nullable disable
|
||||
}
|
||||
8
MainProject/Models/Settings/EncryptionSettings.cs
Normal file
8
MainProject/Models/Settings/EncryptionSettings.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace BasicDotnetTemplate.MainProject.Models.Settings;
|
||||
|
||||
public class EncryptionSettings
|
||||
{
|
||||
#nullable enable
|
||||
public string? Salt { get; set; }
|
||||
#nullable disable
|
||||
}
|
||||
12
MainProject/Models/Settings/JWTSettings.cs
Normal file
12
MainProject/Models/Settings/JWTSettings.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
namespace BasicDotnetTemplate.MainProject.Models.Settings;
|
||||
|
||||
public class JWTSettings
|
||||
{
|
||||
#nullable enable
|
||||
public string? ValidAudience { get; set; }
|
||||
public string? ValidIssuer { get; set; }
|
||||
public string? Secret { get; set; }
|
||||
public int? ExpiredAfterMinsOfInactivity { get; set; }
|
||||
|
||||
#nullable disable
|
||||
}
|
||||
38
MainProject/Services/AuthService.cs
Normal file
38
MainProject/Services/AuthService.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
|
||||
using BasicDotnetTemplate.MainProject.Models.Api.Data.Auth;
|
||||
using BasicDotnetTemplate.MainProject.Models.Api.Common.User;
|
||||
using BasicDotnetTemplate.MainProject.Utils;
|
||||
|
||||
namespace BasicDotnetTemplate.MainProject.Services;
|
||||
|
||||
public interface IAuthService
|
||||
{
|
||||
Task<AuthenticatedUser?> AuthenticateAsync(AuthenticateRequestData data);
|
||||
}
|
||||
|
||||
public class AuthService : BaseService, IAuthService
|
||||
{
|
||||
protected CryptUtils _cryptUtils;
|
||||
|
||||
public AuthService(
|
||||
IConfiguration configuration
|
||||
) : base(configuration)
|
||||
{
|
||||
_cryptUtils = new CryptUtils(_appSettings);
|
||||
}
|
||||
|
||||
public async Task<AuthenticatedUser?> AuthenticateAsync(AuthenticateRequestData data)
|
||||
{
|
||||
AuthenticatedUser? authenticatedUser = null;
|
||||
var decryptedUsername = _cryptUtils.Decrypt(data.Username ?? String.Empty);
|
||||
var decryptedPassword = _cryptUtils.Decrypt(data.Password ?? String.Empty);
|
||||
|
||||
if (!String.IsNullOrEmpty(decryptedUsername) && !String.IsNullOrEmpty(decryptedPassword))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return authenticatedUser;
|
||||
}
|
||||
}
|
||||
|
||||
24
MainProject/Services/BaseService.cs
Normal file
24
MainProject/Services/BaseService.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using BasicDotnetTemplate.MainProject.Models.Settings;
|
||||
|
||||
namespace BasicDotnetTemplate.MainProject.Services;
|
||||
|
||||
public class BaseService
|
||||
{
|
||||
protected readonly IConfiguration _configuration;
|
||||
protected readonly AppSettings _appSettings;
|
||||
|
||||
public BaseService(IConfiguration configuration)
|
||||
{
|
||||
_configuration = configuration;
|
||||
_appSettings = new AppSettings();
|
||||
_configuration.GetSection("AppSettings").Bind(_appSettings);
|
||||
}
|
||||
}
|
||||
|
||||
32
MainProject/Services/JwtService.cs
Normal file
32
MainProject/Services/JwtService.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
|
||||
namespace BasicDotnetTemplate.MainProject.Services;
|
||||
|
||||
public interface IJwtService
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public class JwtService : BaseService, IJwtService
|
||||
{
|
||||
private readonly string _jwtKey;
|
||||
private readonly string _jwtIssuer;
|
||||
private readonly string _jwtAudience;
|
||||
|
||||
public JwtService(
|
||||
IConfiguration configuration
|
||||
) : base(configuration)
|
||||
{
|
||||
_jwtKey = _appSettings?.JWTSettings?.Secret ?? String.Empty;
|
||||
_jwtIssuer = _appSettings?.JWTSettings?.ValidIssuer ?? String.Empty;
|
||||
_jwtAudience = _appSettings?.JWTSettings?.ValidAudience ?? String.Empty;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
59
MainProject/Utils/CryptoUtils.cs
Normal file
59
MainProject/Utils/CryptoUtils.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using BasicDotnetTemplate.MainProject.Models.Settings;
|
||||
|
||||
namespace BasicDotnetTemplate.MainProject.Utils;
|
||||
public class CryptUtils
|
||||
{
|
||||
private readonly string secretKey;
|
||||
private const int M = 16;
|
||||
private const int N = 32;
|
||||
private readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
|
||||
public CryptUtils(AppSettings appSettings)
|
||||
{
|
||||
secretKey = appSettings.EncryptionSettings?.Salt ?? String.Empty;
|
||||
}
|
||||
|
||||
public string Decrypt(string encryptedData)
|
||||
{
|
||||
var decrypted = String.Empty;
|
||||
|
||||
if (String.IsNullOrEmpty(this.secretKey) || this.secretKey.Length < M)
|
||||
{
|
||||
throw new ArgumentException("Unable to proceed with decryption due to invalid settings");
|
||||
}
|
||||
|
||||
if (!String.IsNullOrEmpty(encryptedData) && encryptedData.Length > N)
|
||||
{
|
||||
var iv = encryptedData.Substring(0, M);
|
||||
|
||||
var cipherText = encryptedData.Substring(N);
|
||||
var fullCipher = Convert.FromBase64String(cipherText);
|
||||
|
||||
using (var aes = Aes.Create())
|
||||
{
|
||||
aes.Key = Encoding.UTF8.GetBytes(this.secretKey);
|
||||
aes.IV = Encoding.UTF8.GetBytes(iv);
|
||||
|
||||
using (var decryptor = aes.CreateDecryptor(aes.Key, aes.IV))
|
||||
{
|
||||
using (var msDecrypt = new MemoryStream(fullCipher))
|
||||
{
|
||||
using (var cryptoStream = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
|
||||
{
|
||||
using (var srDecrypt = new StreamReader(cryptoStream))
|
||||
{
|
||||
decrypted = srDecrypt.ReadToEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return decrypted;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ using MongoDB.Driver;
|
||||
using NLog;
|
||||
using BasicDotnetTemplate.MainProject.Core.Database;
|
||||
using BasicDotnetTemplate.MainProject.Models.Settings;
|
||||
using BasicDotnetTemplate.MainProject.Services;
|
||||
|
||||
|
||||
|
||||
@@ -41,7 +42,6 @@ public static class ProgramUtils
|
||||
|
||||
return appSettings;
|
||||
}
|
||||
|
||||
public static OpenApiInfo CreateOpenApiInfo(AppSettings appSettings)
|
||||
{
|
||||
OpenApiInfo openApiInfo = new OpenApiInfo
|
||||
@@ -83,11 +83,53 @@ public static class ProgramUtils
|
||||
builder.Services.AddSwaggerGen(options =>
|
||||
{
|
||||
options.SwaggerDoc("v1", CreateOpenApiInfo(appSettings));
|
||||
|
||||
options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
|
||||
{
|
||||
Description = "Inserisci il Bearer Token nel formato **'Bearer {token}'**",
|
||||
Name = "Authorization",
|
||||
In = ParameterLocation.Header,
|
||||
Type = SecuritySchemeType.Http,
|
||||
Scheme = "Bearer"
|
||||
});
|
||||
|
||||
options.AddSecurityDefinition("ApiKey", new OpenApiSecurityScheme
|
||||
{
|
||||
Description = "Inserisci la tua API Key nel campo appropriato.",
|
||||
Name = "ApiKey",
|
||||
In = ParameterLocation.Header,
|
||||
Type = SecuritySchemeType.ApiKey
|
||||
});
|
||||
|
||||
options.AddSecurityRequirement(new OpenApiSecurityRequirement
|
||||
{
|
||||
{
|
||||
new OpenApiSecurityScheme
|
||||
{
|
||||
Reference = new OpenApiReference
|
||||
{
|
||||
Type = ReferenceType.SecurityScheme,
|
||||
Id = "Bearer"
|
||||
}
|
||||
},
|
||||
new string[] {}
|
||||
},
|
||||
{
|
||||
new OpenApiSecurityScheme
|
||||
{
|
||||
Reference = new OpenApiReference
|
||||
{
|
||||
Type = ReferenceType.SecurityScheme,
|
||||
Id = "ApiKey"
|
||||
}
|
||||
},
|
||||
new string[] {}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Logger.Info("[ProgramUtils][AddOpenApi] Ended swagger doc");
|
||||
}
|
||||
|
||||
public static void AddServices(ref WebApplicationBuilder builder)
|
||||
{
|
||||
Logger.Info("[ProgramUtils][AddServices] Adding services");
|
||||
@@ -99,7 +141,6 @@ public static class ProgramUtils
|
||||
|
||||
Logger.Info("[ProgramUtils][AddServices] Done services");
|
||||
}
|
||||
|
||||
public static void AddMiddlewares(ref WebApplication app)
|
||||
{
|
||||
Logger.Info("[ProgramUtils][AddMiddlewares] Adding middlewares");
|
||||
@@ -126,7 +167,6 @@ public static class ProgramUtils
|
||||
|
||||
Logger.Info("[ProgramUtils][AddMiddlewares] Done middlewares");
|
||||
}
|
||||
|
||||
public static void AddDbContext(ref WebApplicationBuilder builder, AppSettings appSettings)
|
||||
{
|
||||
Logger.Info("[ProgramUtils][AddDbContext] Adding DbContext");
|
||||
@@ -168,10 +208,11 @@ public static class ProgramUtils
|
||||
messages = String.IsNullOrEmpty(messages) ? "No context" : messages;
|
||||
Logger.Info($"[ProgramUtils][AddDbContext] {messages} added");
|
||||
}
|
||||
|
||||
public static void AddScopes(ref WebApplicationBuilder builder)
|
||||
{
|
||||
Logger.Info("[ProgramUtils][AddScopes] Adding scopes");
|
||||
builder.Services.AddScoped<IAuthService, AuthService>();
|
||||
builder.Services.AddScoped<IJwtService, JwtService>();
|
||||
Logger.Info("[ProgramUtils][AddScopes] Done scopes");
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
{
|
||||
"Settings": {
|
||||
"Name": "MainProject",
|
||||
"Version": "v1.0",
|
||||
"Version": "v1",
|
||||
"Description": "This template contains basic configuration for a .Net 8 backend"
|
||||
},
|
||||
"DatabaseSettings": {
|
||||
@@ -27,6 +27,15 @@
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"JWTSettings": {
|
||||
"ValidAudience": "http://localhost:4200",
|
||||
"ValidIssuer": "http://localhost:5000",
|
||||
"Secret": "JWTAuthenticationHIGHsecuredPasswordVVVp1OH7Xzyr",
|
||||
"ExpiredAfterMinsOfInactivity": 15
|
||||
},
|
||||
"EncryptionSettings": {
|
||||
"Salt": "S7VIidfXQf1tOQYX"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user