(feat): white list tokens policy completed
This commit is contained in:
parent
8fc1611d9b
commit
c1e343346d
@ -7,7 +7,7 @@
|
|||||||
"created": {
|
"created": {
|
||||||
"$date": "2022-01-01T00:00:00.000Z"
|
"$date": "2022-01-01T00:00:00.000Z"
|
||||||
},
|
},
|
||||||
"nickaName": "admin",
|
"username": "admin",
|
||||||
"passwords": {
|
"passwords": {
|
||||||
"password": {
|
"password": {
|
||||||
"hash": "pznndK3nv9bftf/qQxqBy4VjH7Ow9vx2Kd6376oJuqQ=",
|
"hash": "pznndK3nv9bftf/qQxqBy4VjH7Ow9vx2Kd6376oJuqQ=",
|
||||||
@ -3,7 +3,7 @@ using Core.Enumerations;
|
|||||||
|
|
||||||
namespace Core.DomainObjects {
|
namespace Core.DomainObjects {
|
||||||
public class Contact : DomainObjectBase<Contact> {
|
public class Contact : DomainObjectBase<Contact> {
|
||||||
public ContactTypes ContactType { get; set; }
|
public ContactTypes Type { get; set; }
|
||||||
public string Value { get; set; }
|
public string Value { get; set; }
|
||||||
public bool Confirmed { get; set; }
|
public bool Confirmed { get; set; }
|
||||||
|
|
||||||
|
|||||||
@ -8,7 +8,7 @@ namespace Core.DomainObjects {
|
|||||||
|
|
||||||
public DateTime Created { get; set; }
|
public DateTime Created { get; set; }
|
||||||
|
|
||||||
public string NickName { get; set; }
|
public string Username { get; set; }
|
||||||
|
|
||||||
public Passwords Passwords { get; set; }
|
public Passwords Passwords { get; set; }
|
||||||
|
|
||||||
|
|||||||
17
webapi/CryptoProvider/AesKey.cs
Normal file
17
webapi/CryptoProvider/AesKey.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace CryptoProvider {
|
||||||
|
public interface IAesKey {
|
||||||
|
public string? IV { get; set; }
|
||||||
|
public string? Key { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AesKey : IAesKey {
|
||||||
|
public string? IV { get; set; }
|
||||||
|
public string? Key { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
77
webapi/CryptoProvider/AesService.cs
Normal file
77
webapi/CryptoProvider/AesService.cs
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
using System.Text;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
|
|
||||||
|
namespace CryptoProvider {
|
||||||
|
|
||||||
|
public static class AesService {
|
||||||
|
|
||||||
|
public static IAesKey GenerateKey() {
|
||||||
|
using var aes = Aes.Create();
|
||||||
|
|
||||||
|
aes.GenerateIV();
|
||||||
|
aes.GenerateKey();
|
||||||
|
|
||||||
|
return new AesKey {
|
||||||
|
IV = Convert.ToBase64String(aes.IV),
|
||||||
|
Key = Convert.ToBase64String(aes.Key)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string EncryptString(string key, string plainText) =>
|
||||||
|
EncryptStringCore(new byte[16], Convert.FromBase64String(key), plainText);
|
||||||
|
|
||||||
|
public static string EncryptString(string iv, string key, string plainText) =>
|
||||||
|
EncryptStringCore(Convert.FromBase64String(iv), Convert.FromBase64String(key), plainText);
|
||||||
|
|
||||||
|
public static string DecryptString(string key, string cipherText) =>
|
||||||
|
DecryptStringCore(new byte[16], Convert.FromBase64String(key), cipherText);
|
||||||
|
|
||||||
|
public static string DecryptString(string iv, string key, string cipherText) =>
|
||||||
|
DecryptStringCore(Convert.FromBase64String(iv), Convert.FromBase64String(key), cipherText);
|
||||||
|
|
||||||
|
#region Core methods
|
||||||
|
private static string EncryptStringCore(byte[] iv, byte[] key, string plainText) {
|
||||||
|
byte[] array;
|
||||||
|
|
||||||
|
using var aes = Aes.Create();
|
||||||
|
|
||||||
|
aes.Key = key;
|
||||||
|
aes.IV = iv;
|
||||||
|
|
||||||
|
var encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
|
||||||
|
|
||||||
|
using var memoryStream = new MemoryStream();
|
||||||
|
using var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);
|
||||||
|
using var streamWriter = new StreamWriter(cryptoStream);
|
||||||
|
|
||||||
|
streamWriter.Write(plainText);
|
||||||
|
streamWriter.Flush();
|
||||||
|
cryptoStream.FlushFinalBlock();
|
||||||
|
|
||||||
|
array = memoryStream.ToArray();
|
||||||
|
|
||||||
|
return Convert.ToBase64String(array);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string DecryptStringCore(byte [] iv, byte [] key, string cipherText) {
|
||||||
|
byte[] buffer = Convert.FromBase64String(cipherText);
|
||||||
|
|
||||||
|
using var aes = Aes.Create();
|
||||||
|
|
||||||
|
|
||||||
|
aes.Key = key;
|
||||||
|
aes.IV = iv;
|
||||||
|
|
||||||
|
var decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
|
||||||
|
|
||||||
|
using var memoryStream = new MemoryStream(buffer);
|
||||||
|
using var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);
|
||||||
|
using var streamReader = new StreamReader(cryptoStream);
|
||||||
|
|
||||||
|
return streamReader.ReadToEnd();
|
||||||
|
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -7,10 +7,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="DomainResult.Common" Version="3.0.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="6.0.10" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="6.0.8" />
|
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
|
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
|
|
||||||
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
@ -2,14 +2,10 @@
|
|||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using Microsoft.AspNetCore.Cryptography.KeyDerivation;
|
using Microsoft.AspNetCore.Cryptography.KeyDerivation;
|
||||||
|
|
||||||
namespace HashService {
|
namespace CryptoProvider {
|
||||||
|
|
||||||
public interface IHashService {
|
public static class HashService {
|
||||||
(string, string) CreateSaltedHash(string value);
|
private static string CreateSalt() {
|
||||||
bool ValidateHash(string value, string salt, string hash);
|
|
||||||
}
|
|
||||||
public class HashService : IHashService {
|
|
||||||
private string CreateSalt() {
|
|
||||||
byte[] randomBytes = new byte[128 / 8];
|
byte[] randomBytes = new byte[128 / 8];
|
||||||
using (var generator = RandomNumberGenerator.Create()) {
|
using (var generator = RandomNumberGenerator.Create()) {
|
||||||
generator.GetBytes(randomBytes);
|
generator.GetBytes(randomBytes);
|
||||||
@ -17,7 +13,7 @@ namespace HashService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string CreateHash(string value, string salt) {
|
private static string CreateHash(string value, string salt) {
|
||||||
var valueBytes = KeyDerivation.Pbkdf2(
|
var valueBytes = KeyDerivation.Pbkdf2(
|
||||||
password: value,
|
password: value,
|
||||||
salt: Encoding.UTF8.GetBytes(salt),
|
salt: Encoding.UTF8.GetBytes(salt),
|
||||||
@ -28,14 +24,14 @@ namespace HashService {
|
|||||||
return Convert.ToBase64String(valueBytes);
|
return Convert.ToBase64String(valueBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public (string, string) CreateSaltedHash(string value) {
|
public static (string, string) CreateSaltedHash(string value) {
|
||||||
var salt = CreateSalt();
|
var salt = CreateSalt();
|
||||||
var hash = CreateHash(value, salt);
|
var hash = CreateHash(value, salt);
|
||||||
|
|
||||||
return (salt, hash);
|
return (salt, hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ValidateHash(string value, string salt, string hash) =>
|
public static bool ValidateHash(string value, string salt, string hash) =>
|
||||||
CreateHash(value, salt) == hash;
|
CreateHash(value, salt) == hash;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -15,7 +15,9 @@ namespace DataProviders.Collections {
|
|||||||
public interface IUserDataProvider {
|
public interface IUserDataProvider {
|
||||||
(User?, IDomainResult) Get(Guid userId);
|
(User?, IDomainResult) Get(Guid userId);
|
||||||
|
|
||||||
(User?, IDomainResult) GetByNickName(string nickName);
|
(User?, IDomainResult) GetByUsername(string nickName);
|
||||||
|
|
||||||
|
(Guid?, IDomainResult) Update(User user);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class UserDataProvider : CollectionDataProviderBase<User>, IUserDataProvider {
|
public class UserDataProvider : CollectionDataProviderBase<User>, IUserDataProvider {
|
||||||
@ -38,13 +40,17 @@ namespace DataProviders.Collections {
|
|||||||
return (list.First(), result);
|
return (list.First(), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public (User?, IDomainResult) GetByNickName(string nickName) {
|
public (User?, IDomainResult) GetByUsername(string username) {
|
||||||
var (list, result) = GetWithPredicate(x => x.NickName == nickName, _collectionName);
|
var (list, result) = GetWithPredicate(x => x.Username == username, _collectionName);
|
||||||
|
|
||||||
if (!result.IsSuccess || list == null)
|
if (!result.IsSuccess || list == null)
|
||||||
return (null, result);
|
return (null, result);
|
||||||
|
|
||||||
return (list.First(), result);
|
return (list.First(), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public (Guid?, IDomainResult) Update(User user) =>
|
||||||
|
UpdateWithPredicate(user, x => x.Id == user.Id, _collectionName);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
55
webapi/DataProviders/Converters/EnumerationListSerializer.cs
Normal file
55
webapi/DataProviders/Converters/EnumerationListSerializer.cs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
using MongoDB.Bson;
|
||||||
|
using MongoDB.Bson.IO;
|
||||||
|
using MongoDB.Bson.Serialization;
|
||||||
|
using Core.Abstractions;
|
||||||
|
|
||||||
|
namespace DataProviders.Converters {
|
||||||
|
public class EnumerationListSerializer<T> : IBsonSerializer<List<T>>, IBsonArraySerializer where T : Enumeration {
|
||||||
|
private List<T> Deserialize(IBsonReader reader) {
|
||||||
|
var type = reader.GetCurrentBsonType();
|
||||||
|
var response = new List<T>();
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case BsonType.Array:
|
||||||
|
reader.ReadStartArray();
|
||||||
|
while (reader.ReadBsonType() != BsonType.EndOfDocument) {
|
||||||
|
response.Add(Enumeration.FromValue<T>(BsonSerializer.Deserialize<int>(reader)));
|
||||||
|
}
|
||||||
|
|
||||||
|
reader.ReadEndArray();
|
||||||
|
return response;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new NotImplementedException($"No implementation to deserialize {type}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void Serialize(IBsonWriter writer, List<T> values) {
|
||||||
|
if (values != null) {
|
||||||
|
writer.WriteStartArray();
|
||||||
|
|
||||||
|
foreach (var value in values) {
|
||||||
|
writer.WriteInt32(value.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.WriteEndArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type ValueType { get => typeof(List<T>); }
|
||||||
|
|
||||||
|
public object Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) => Deserialize(context.Reader);
|
||||||
|
public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, object value) => Serialize(context.Writer, (List<T>)value);
|
||||||
|
|
||||||
|
List<T> IBsonSerializer<List<T>>.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) => Deserialize(context.Reader);
|
||||||
|
public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, List<T> value) => Serialize(context.Writer, value);
|
||||||
|
|
||||||
|
public bool TryGetItemSerializationInfo(out BsonSerializationInfo serializationInfo) {
|
||||||
|
string elementName = null;
|
||||||
|
var serializer = BsonSerializer.LookupSerializer(typeof(string));
|
||||||
|
var nominalType = typeof(string);
|
||||||
|
serializationInfo = new BsonSerializationInfo(elementName, serializer, nominalType);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -6,65 +6,22 @@ using Core.Abstractions;
|
|||||||
namespace DataProviders.Converters {
|
namespace DataProviders.Converters {
|
||||||
|
|
||||||
public class EnumerationSerializer<T> : IBsonSerializer<T> where T : Enumeration {
|
public class EnumerationSerializer<T> : IBsonSerializer<T> where T : Enumeration {
|
||||||
|
|
||||||
private T Deserialize(IBsonReader reader) => Enumeration.FromValue<T>(BsonSerializer.Deserialize<int>(reader));
|
private T Deserialize(IBsonReader reader) => Enumeration.FromValue<T>(BsonSerializer.Deserialize<int>(reader));
|
||||||
private void Serialize(IBsonWriter writer, T value) => BsonSerializer.Serialize(writer, value.Id);
|
private void Serialize(IBsonWriter writer, T value) => BsonSerializer.Serialize(writer, value.Id);
|
||||||
|
|
||||||
public Type ValueType { get => typeof(T); }
|
public Type ValueType { get => typeof(T); }
|
||||||
|
|
||||||
public object Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) => Deserialize(context.Reader);
|
public T Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) =>
|
||||||
public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, object value) => Serialize(context.Writer, (T)value);
|
Deserialize(context.Reader);
|
||||||
|
|
||||||
|
public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, T value) =>
|
||||||
|
Serialize(context.Writer, value);
|
||||||
|
|
||||||
T IBsonSerializer<T>.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) => Deserialize(context.Reader);
|
public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, object value) =>
|
||||||
public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, T value) => Serialize(context.Writer, value);
|
Serialize(context.Writer, (T)value);
|
||||||
}
|
|
||||||
|
|
||||||
public class EnumerationListSerializer<T> : IBsonSerializer<List<T>>, IBsonArraySerializer where T : Enumeration {
|
object IBsonSerializer.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) =>
|
||||||
private List<T> Deserialize(IBsonReader reader) {
|
Deserialize(context.Reader);
|
||||||
var type = reader.GetCurrentBsonType();
|
|
||||||
var response = new List<T>();
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case BsonType.Array:
|
|
||||||
reader.ReadStartArray();
|
|
||||||
while (reader.ReadBsonType() != BsonType.EndOfDocument) {
|
|
||||||
response.Add(Enumeration.FromValue<T>(BsonSerializer.Deserialize<int>(reader)));
|
|
||||||
}
|
|
||||||
|
|
||||||
reader.ReadEndArray();
|
|
||||||
return response;
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new NotImplementedException($"No implementation to deserialize {type}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private void Serialize(IBsonWriter writer, List<T> values) {
|
|
||||||
if (values != null) {
|
|
||||||
writer.WriteStartArray();
|
|
||||||
|
|
||||||
foreach (var value in values) {
|
|
||||||
writer.WriteInt32(value.Id);
|
|
||||||
}
|
|
||||||
|
|
||||||
writer.WriteEndArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public Type ValueType { get => typeof(List<T>); }
|
|
||||||
|
|
||||||
public object Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) => Deserialize(context.Reader);
|
|
||||||
public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, object value) => Serialize(context.Writer, (List<T>)value);
|
|
||||||
|
|
||||||
List<T> IBsonSerializer<List<T>>.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) => Deserialize(context.Reader);
|
|
||||||
public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, List<T> value) => Serialize(context.Writer, value);
|
|
||||||
|
|
||||||
public bool TryGetItemSerializationInfo(out BsonSerializationInfo serializationInfo) {
|
|
||||||
string elementName = null;
|
|
||||||
var serializer = BsonSerializer.LookupSerializer(typeof(string));
|
|
||||||
var nominalType = typeof(string);
|
|
||||||
serializationInfo = new BsonSerializationInfo(elementName, serializer, nominalType);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,10 +8,10 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="DomainResult.Common" Version="3.0.0" />
|
<PackageReference Include="DomainResult.Common" Version="3.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.1" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
|
||||||
<PackageReference Include="MongoDB.Driver" Version="2.17.1" />
|
<PackageReference Include="MongoDB.Driver" Version="2.18.0" />
|
||||||
<PackageReference Include="MongoDB.Driver.GridFS" Version="2.17.1" />
|
<PackageReference Include="MongoDB.Driver.GridFS" Version="2.18.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@ -13,6 +13,8 @@ namespace DataProviders.Extensions
|
|||||||
public static void RegisterDataproviders(this IServiceCollection services, IDataProvidersConfig appSettings) {
|
public static void RegisterDataproviders(this IServiceCollection services, IDataProvidersConfig appSettings) {
|
||||||
var config = appSettings.Database;
|
var config = appSettings.Database;
|
||||||
|
|
||||||
|
if (config == null) throw new NullReferenceException();
|
||||||
|
|
||||||
services.AddSingleton<IMongoClient>(x => new MongoClient(config.ConnectionString));
|
services.AddSingleton<IMongoClient>(x => new MongoClient(config.ConnectionString));
|
||||||
services.AddSingleton<IIdGenerator, GuidGenerator>();
|
services.AddSingleton<IIdGenerator, GuidGenerator>();
|
||||||
|
|
||||||
|
|||||||
@ -87,7 +87,7 @@ namespace DataProviders {
|
|||||||
BsonClassMap.RegisterClassMap<Contact>(cm => {
|
BsonClassMap.RegisterClassMap<Contact>(cm => {
|
||||||
cm.AutoMap();
|
cm.AutoMap();
|
||||||
|
|
||||||
cm.GetMemberMap(c => c.ContactType)
|
cm.GetMemberMap(c => c.Type)
|
||||||
.SetSerializer(new EnumerationSerializer<ContactTypes>());
|
.SetSerializer(new EnumerationSerializer<ContactTypes>());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,11 +2,6 @@
|
|||||||
using ImageProvider.Fonts;
|
using ImageProvider.Fonts;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using SixLabors.Fonts;
|
using SixLabors.Fonts;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace ImageProvider {
|
namespace ImageProvider {
|
||||||
|
|
||||||
@ -8,14 +8,15 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="DomainResult.Common" Version="3.0.0" />
|
<PackageReference Include="DomainResult.Common" Version="3.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.1" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.2" />
|
||||||
<PackageReference Include="SixLabors.Fonts" Version="1.0.0-beta0013" />
|
<PackageReference Include="SixLabors.Fonts" Version="1.0.0-beta0013" />
|
||||||
<PackageReference Include="SixLabors.ImageSharp" Version="2.1.3" />
|
<PackageReference Include="SixLabors.ImageSharp" Version="2.1.3" />
|
||||||
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta11" />
|
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta11" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\DataProviders\DataProviders.csproj" />
|
<ProjectReference Include="..\Core\Core.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@ -10,7 +10,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.14.0" />
|
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.17.0" />
|
||||||
<PackageReference Include="Yarp.ReverseProxy" Version="1.1.0" />
|
<PackageReference Include="Yarp.ReverseProxy" Version="1.1.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="DomainResult.Common" Version="3.0.0" />
|
<PackageReference Include="DomainResult.Common" Version="3.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.1" />
|
||||||
<PackageReference Include="nClam" Version="7.0.0" />
|
<PackageReference Include="nClam" Version="7.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +0,0 @@
|
|||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
|
|
||||||
namespace HashService.Extensions {
|
|
||||||
public static class ServiceCollectionExtensions {
|
|
||||||
|
|
||||||
public static void RegisterHashService(this IServiceCollection services) {
|
|
||||||
|
|
||||||
services.AddSingleton<IHashService, HashService>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -8,9 +8,9 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="DomainResult.Common" Version="3.0.0" />
|
<PackageReference Include="DomainResult.Common" Version="3.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.1" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
|
||||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.18.0" />
|
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.24.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@ -12,11 +12,11 @@
|
|||||||
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="6.0.1" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="6.0.1" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="6.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="6.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="6.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="6.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.1" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
|
||||||
<PackageReference Include="MongoDB.Driver" Version="2.17.1" />
|
<PackageReference Include="MongoDB.Driver" Version="2.18.0" />
|
||||||
<PackageReference Include="xunit" Version="2.4.1" />
|
<PackageReference Include="xunit" Version="2.4.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@ -9,10 +9,10 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.1" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="6.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="6.0.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
|
||||||
<PackageReference Include="xunit" Version="2.4.1" />
|
<PackageReference Include="xunit" Version="2.4.2" />
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
|||||||
@ -7,8 +7,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WeatherForecast", "WeatherF
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Services", "Services", "{113EE574-E047-4727-AA36-841F845504D5}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Services", "Services", "{113EE574-E047-4727-AA36-841F845504D5}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HashService", "Services\HashService\HashService.csproj", "{B8F84A37-B54B-4606-9BC3-6FEB96A5A34B}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JWTService", "Services\JWTService\JWTService.csproj", "{B717D8BD-BCCA-4515-9A62-CA3BE802D0F7}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JWTService", "Services\JWTService\JWTService.csproj", "{B717D8BD-BCCA-4515-9A62-CA3BE802D0F7}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Core", "Core\Core.csproj", "{BCDED8EB-97B0-4067-BB0A-23F94D1A1288}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Core", "Core\Core.csproj", "{BCDED8EB-97B0-4067-BB0A-23F94D1A1288}"
|
||||||
@ -25,7 +23,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ExtensionsTests", "Tests\Ex
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CoreTests", "Tests\Core\CoreTests.csproj", "{04CB9827-AA6D-4708-A26D-8420C842506D}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CoreTests", "Tests\Core\CoreTests.csproj", "{04CB9827-AA6D-4708-A26D-8420C842506D}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageProvider", "Services\ImageProvider\ImageProvider.csproj", "{16552644-D7EE-4B4A-A725-79909A8103DE}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageProvider", "ImageProvider\ImageProvider.csproj", "{16552644-D7EE-4B4A-A725-79909A8103DE}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileSecurityService", "Services\FileSecurityService\FileSecurityService.csproj", "{AD515653-9145-4894-9017-0ABA5A5892F4}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileSecurityService", "Services\FileSecurityService\FileSecurityService.csproj", "{AD515653-9145-4894-9017-0ABA5A5892F4}"
|
||||||
EndProject
|
EndProject
|
||||||
@ -33,6 +31,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReverseProxy", "ReverseProx
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-compose.dcproj", "{7FC6F0BA-2DCB-4B53-A3B3-61CEEF42B9D0}"
|
Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-compose.dcproj", "{7FC6F0BA-2DCB-4B53-A3B3-61CEEF42B9D0}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CryptoProvider", "CryptoProvider\CryptoProvider.csproj", "{E90379CB-BC2D-452F-9F92-24A7B46195D4}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@ -43,10 +43,6 @@ Global
|
|||||||
{065AC673-3C4D-4C08-B1A9-3C3A1467B3A7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{065AC673-3C4D-4C08-B1A9-3C3A1467B3A7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{065AC673-3C4D-4C08-B1A9-3C3A1467B3A7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{065AC673-3C4D-4C08-B1A9-3C3A1467B3A7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{065AC673-3C4D-4C08-B1A9-3C3A1467B3A7}.Release|Any CPU.Build.0 = Release|Any CPU
|
{065AC673-3C4D-4C08-B1A9-3C3A1467B3A7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{B8F84A37-B54B-4606-9BC3-6FEB96A5A34B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{B8F84A37-B54B-4606-9BC3-6FEB96A5A34B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{B8F84A37-B54B-4606-9BC3-6FEB96A5A34B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{B8F84A37-B54B-4606-9BC3-6FEB96A5A34B}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{B717D8BD-BCCA-4515-9A62-CA3BE802D0F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{B717D8BD-BCCA-4515-9A62-CA3BE802D0F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{B717D8BD-BCCA-4515-9A62-CA3BE802D0F7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{B717D8BD-BCCA-4515-9A62-CA3BE802D0F7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{B717D8BD-BCCA-4515-9A62-CA3BE802D0F7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{B717D8BD-BCCA-4515-9A62-CA3BE802D0F7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
@ -91,16 +87,18 @@ Global
|
|||||||
{7FC6F0BA-2DCB-4B53-A3B3-61CEEF42B9D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{7FC6F0BA-2DCB-4B53-A3B3-61CEEF42B9D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{7FC6F0BA-2DCB-4B53-A3B3-61CEEF42B9D0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{7FC6F0BA-2DCB-4B53-A3B3-61CEEF42B9D0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{7FC6F0BA-2DCB-4B53-A3B3-61CEEF42B9D0}.Release|Any CPU.Build.0 = Release|Any CPU
|
{7FC6F0BA-2DCB-4B53-A3B3-61CEEF42B9D0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{E90379CB-BC2D-452F-9F92-24A7B46195D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{E90379CB-BC2D-452F-9F92-24A7B46195D4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{E90379CB-BC2D-452F-9F92-24A7B46195D4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{E90379CB-BC2D-452F-9F92-24A7B46195D4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(NestedProjects) = preSolution
|
GlobalSection(NestedProjects) = preSolution
|
||||||
{B8F84A37-B54B-4606-9BC3-6FEB96A5A34B} = {113EE574-E047-4727-AA36-841F845504D5}
|
|
||||||
{B717D8BD-BCCA-4515-9A62-CA3BE802D0F7} = {113EE574-E047-4727-AA36-841F845504D5}
|
{B717D8BD-BCCA-4515-9A62-CA3BE802D0F7} = {113EE574-E047-4727-AA36-841F845504D5}
|
||||||
{43315A1D-9E09-4398-84B9-A9D9D623AE5A} = {216302C2-64DE-4AE7-BC14-BDAC5B732472}
|
{43315A1D-9E09-4398-84B9-A9D9D623AE5A} = {216302C2-64DE-4AE7-BC14-BDAC5B732472}
|
||||||
{04CB9827-AA6D-4708-A26D-8420C842506D} = {216302C2-64DE-4AE7-BC14-BDAC5B732472}
|
{04CB9827-AA6D-4708-A26D-8420C842506D} = {216302C2-64DE-4AE7-BC14-BDAC5B732472}
|
||||||
{16552644-D7EE-4B4A-A725-79909A8103DE} = {113EE574-E047-4727-AA36-841F845504D5}
|
|
||||||
{AD515653-9145-4894-9017-0ABA5A5892F4} = {113EE574-E047-4727-AA36-841F845504D5}
|
{AD515653-9145-4894-9017-0ABA5A5892F4} = {113EE574-E047-4727-AA36-841F845504D5}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using DataProviders;
|
using CryptoProvider;
|
||||||
|
using DataProviders;
|
||||||
using JWTService;
|
using JWTService;
|
||||||
|
|
||||||
namespace WeatherForecast {
|
namespace WeatherForecast {
|
||||||
@ -13,6 +14,11 @@ namespace WeatherForecast {
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public JwtConfig? JwtConfig { get; set; }
|
public JwtConfig? JwtConfig { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public AesKey? JwtTokenEncryption { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -11,7 +11,7 @@ namespace WeatherForecast.Controllers;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[AllowAnonymous]
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("api/[controller]")]
|
[Route("api/[controller]")]
|
||||||
public class AuthenticationController : ControllerBase {
|
public class AuthenticationController : ControllerBase {
|
||||||
@ -29,15 +29,26 @@ public class AuthenticationController : ControllerBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
/// By providing username and password user obtains jwt token
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="siteId"></param>
|
|
||||||
/// <param name="requestData"></param>
|
/// <param name="requestData"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[HttpPost("{siteId}")]
|
[AllowAnonymous]
|
||||||
public IActionResult Post([FromRoute] Guid siteId, [FromBody] AuthenticationRequestModel requestData) {
|
[HttpPost()]
|
||||||
var result = _authenticationService.Post(siteId, requestData);
|
public IActionResult Post([FromBody] AuthenticationRequestModel requestData) {
|
||||||
|
var result = _authenticationService.Post(requestData);
|
||||||
return result.ToActionResult();
|
return result.ToActionResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
[Authorize(Policy = "WhitelistToken")]
|
||||||
|
[HttpGet()]
|
||||||
|
|
||||||
|
public IActionResult Get() {
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -11,7 +11,7 @@ namespace WeatherForecast.Controllers;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Authorize(Policy = "")]
|
[Authorize(Policy = "WhitelistToken")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("api/[controller]")]
|
[Route("api/[controller]")]
|
||||||
public class BlogItemController : ControllerBase {
|
public class BlogItemController : ControllerBase {
|
||||||
|
|||||||
@ -10,7 +10,7 @@ namespace WeatherForecast.Controllers;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Authorize(Policy = "")]
|
[Authorize(Policy = "WhitelistToken")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("api/[controller]")]
|
[Route("api/[controller]")]
|
||||||
public class BlogItemsController : ControllerBase {
|
public class BlogItemsController : ControllerBase {
|
||||||
|
|||||||
@ -11,7 +11,7 @@ namespace WeatherForecast.Controllers;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Authorize]
|
[Authorize(Policy = "WhitelistToken")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("api/[controller]")]
|
[Route("api/[controller]")]
|
||||||
public class CategoryItemController : ControllerBase {
|
public class CategoryItemController : ControllerBase {
|
||||||
|
|||||||
@ -10,7 +10,7 @@ namespace WeatherForecast.Controllers;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Authorize]
|
[Authorize(Policy = "WhitelistToken")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("api/[controller]")]
|
[Route("api/[controller]")]
|
||||||
public class CategoryItemsController : ControllerBase {
|
public class CategoryItemsController : ControllerBase {
|
||||||
|
|||||||
@ -9,7 +9,7 @@ namespace WeatherForecast.Controllers;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Authorize]
|
[Authorize(Policy = "WhitelistToken")]
|
||||||
[AllowAnonymous]
|
[AllowAnonymous]
|
||||||
[Route("api/[controller]")]
|
[Route("api/[controller]")]
|
||||||
public class FileController : Controller {
|
public class FileController : Controller {
|
||||||
|
|||||||
@ -8,7 +8,7 @@ namespace WeatherForecast.Controllers;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Authorize]
|
[Authorize(Policy = "WhitelistToken")]
|
||||||
[AllowAnonymous]
|
[AllowAnonymous]
|
||||||
[Route("api/[controller]")]
|
[Route("api/[controller]")]
|
||||||
public class FilesController : Controller {
|
public class FilesController : Controller {
|
||||||
|
|||||||
@ -10,7 +10,7 @@ namespace WeatherForecast.Controllers;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Authorize]
|
[Authorize(Policy = "WhitelistToken")]
|
||||||
[Route("api/[controller]")]
|
[Route("api/[controller]")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
public class PasswordController : ControllerBase {
|
public class PasswordController : ControllerBase {
|
||||||
|
|||||||
@ -12,7 +12,7 @@ namespace WeatherForecast.Controllers;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Authorize]
|
[Authorize(Policy = "WhitelistToken")]
|
||||||
[AllowAnonymous]
|
[AllowAnonymous]
|
||||||
[Route("api/[controller]")]
|
[Route("api/[controller]")]
|
||||||
public class ShopCartItemController : ControllerBase {
|
public class ShopCartItemController : ControllerBase {
|
||||||
|
|||||||
@ -11,7 +11,7 @@ namespace WeatherForecast.Controllers;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Authorize]
|
[Authorize(Policy = "WhitelistToken")]
|
||||||
[AllowAnonymous]
|
[AllowAnonymous]
|
||||||
[Route("api/[controller]")]
|
[Route("api/[controller]")]
|
||||||
public class ShopCartItemsController : ControllerBase {
|
public class ShopCartItemsController : ControllerBase {
|
||||||
|
|||||||
@ -11,7 +11,7 @@ namespace WeatherForecast.Controllers;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Authorize]
|
[Authorize(Policy = "WhitelistToken")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("api/[controller]")]
|
[Route("api/[controller]")]
|
||||||
public class ShopItemController : ControllerBase {
|
public class ShopItemController : ControllerBase {
|
||||||
|
|||||||
@ -10,7 +10,7 @@ namespace WeatherForecast.Controllers;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Authorize]
|
[Authorize(Policy = "WhitelistToken")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("api/[controller]")]
|
[Route("api/[controller]")]
|
||||||
public class ShopItemsController : ControllerBase {
|
public class ShopItemsController : ControllerBase {
|
||||||
|
|||||||
@ -6,7 +6,7 @@ namespace WeatherForecast.Controllers;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Authorize]
|
[Authorize(Policy = "WhitelistToken")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("api/[controller]")]
|
[Route("api/[controller]")]
|
||||||
public class UserController : ControllerBase {
|
public class UserController : ControllerBase {
|
||||||
|
|||||||
55
webapi/WeatherForecast/Policies/WhitelistToken.cs
Normal file
55
webapi/WeatherForecast/Policies/WhitelistToken.cs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
using Extensions;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using WeatherForecast.Services;
|
||||||
|
|
||||||
|
namespace WeatherForecast.Policies {
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public class WhitelistTokenRequirement : IAuthorizationRequirement {
|
||||||
|
// public string WhiteListToken { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public WhitelistTokenRequirement() {
|
||||||
|
// WhiteListToken = whiteListToken;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public class WhitelistTokenHandler : AuthorizationHandler<WhitelistTokenRequirement> {
|
||||||
|
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||||
|
private readonly IAuthenticationService _athenticationService;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="httpContextAccessor"></param>
|
||||||
|
/// <param name="athenticationService"></param>
|
||||||
|
public WhitelistTokenHandler(
|
||||||
|
IHttpContextAccessor httpContextAccessor,
|
||||||
|
IAuthenticationService athenticationService
|
||||||
|
) {
|
||||||
|
_httpContextAccessor = httpContextAccessor;
|
||||||
|
_athenticationService = athenticationService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context"></param>
|
||||||
|
/// <param name="requirement"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, WhitelistTokenRequirement requirement) {
|
||||||
|
var request = _httpContextAccessor?.HttpContext?.Request;
|
||||||
|
|
||||||
|
if (request != null && _athenticationService.Get(request.GeBearerToken()).IsSuccess)
|
||||||
|
context.Succeed(requirement);
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,9 +3,10 @@ using Core.DomainObjects;
|
|||||||
using DataProviders.Collections;
|
using DataProviders.Collections;
|
||||||
using DomainResults.Common;
|
using DomainResults.Common;
|
||||||
using ExtensionMethods;
|
using ExtensionMethods;
|
||||||
using HashService;
|
using CryptoProvider;
|
||||||
using JWTService;
|
using JWTService;
|
||||||
using WeatherForecast.Models.Requests;
|
using WeatherForecast.Models.Requests;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
namespace WeatherForecast.Services {
|
namespace WeatherForecast.Services {
|
||||||
|
|
||||||
@ -17,10 +18,16 @@ namespace WeatherForecast.Services {
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="siteId"></param>
|
|
||||||
/// <param name="requestData"></param>
|
/// <param name="requestData"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
(string?, IDomainResult) Post(Guid siteId, AuthenticationRequestModel requestData);
|
(string?, IDomainResult) Post(AuthenticationRequestModel requestData);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
IDomainResult Get(string? token);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -28,56 +35,59 @@ namespace WeatherForecast.Services {
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class AutheticationService : ServiceBase<AutheticationService>, IAuthenticationService {
|
public class AutheticationService : ServiceBase<AutheticationService>, IAuthenticationService {
|
||||||
|
|
||||||
|
private readonly IAesKey? _aesKey;
|
||||||
private readonly IUserDataProvider _userDataProvider;
|
private readonly IUserDataProvider _userDataProvider;
|
||||||
private readonly IHashService _hashService;
|
|
||||||
private readonly IJWTService _jwtService;
|
private readonly IJWTService _jwtService;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="logger"></param>
|
/// <param name="logger"></param>
|
||||||
|
/// <param name="options"></param>
|
||||||
/// <param name="userDataProvider"></param>
|
/// <param name="userDataProvider"></param>
|
||||||
/// <param name="hashService"></param>
|
|
||||||
/// <param name="jwtService"></param>
|
/// <param name="jwtService"></param>
|
||||||
public AutheticationService (
|
public AutheticationService (
|
||||||
ILogger<AutheticationService> logger,
|
ILogger<AutheticationService> logger,
|
||||||
|
IOptions<Configuration> options,
|
||||||
IUserDataProvider userDataProvider,
|
IUserDataProvider userDataProvider,
|
||||||
IHashService hashService,
|
|
||||||
IJWTService jwtService
|
IJWTService jwtService
|
||||||
) : base(logger) {
|
) : base(logger) {
|
||||||
|
_aesKey = options.Value.JwtTokenEncryption;
|
||||||
_userDataProvider = userDataProvider;
|
_userDataProvider = userDataProvider;
|
||||||
_hashService = hashService;
|
|
||||||
_jwtService = jwtService;
|
_jwtService = jwtService;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="siteId"></param>
|
|
||||||
/// <param name="requestData"></param>
|
/// <param name="requestData"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public (string?, IDomainResult) Post(Guid siteId, AuthenticationRequestModel requestData) {
|
public (string?, IDomainResult) Post(AuthenticationRequestModel requestData) {
|
||||||
var opId = Guid.NewGuid();
|
|
||||||
|
if (_aesKey?.IV == null || _aesKey?.Key == null)
|
||||||
|
return IDomainResult.Failed<string?>("IV or Key are not set");
|
||||||
|
|
||||||
// Retrieve user from database by userName
|
// Retrieve user from database by userName
|
||||||
var (user, getUserResult) = _userDataProvider.GetByNickName(requestData.Username);
|
var (user, getUserResult) = _userDataProvider.GetByUsername(requestData.Username);
|
||||||
if (!getUserResult.IsSuccess || user == null)
|
if (!getUserResult.IsSuccess || user == null)
|
||||||
return IDomainResult.NotFound<string?>();
|
return (null, getUserResult);
|
||||||
|
|
||||||
if (user.Passwords.Password == null)
|
if (user.Passwords.Password == null)
|
||||||
return IDomainResult.Failed<string?>($"Opid = [{opId}] Password is not set, create new password.");
|
return IDomainResult.Failed<string?>("Password is not set, create new password.");
|
||||||
|
|
||||||
// Check provided password hash with the stored one
|
// Check provided password hash with the stored one
|
||||||
var (salt, hash) = _hashService.CreateSaltedHash(requestData.Password);
|
var (salt, hash) = HashService.CreateSaltedHash(requestData.Password);
|
||||||
if (!_hashService.ValidateHash(requestData.Password, salt, hash))
|
if (!HashService.ValidateHash(requestData.Password, salt, hash))
|
||||||
return IDomainResult.Unauthorized<string?>();
|
return IDomainResult.Unauthorized<string?>();
|
||||||
|
|
||||||
// Check password expiration if enabled
|
// Check password expiration if enabled
|
||||||
if (user.Passwords.Expiration.Enabled && DateTime.UtcNow > user.Passwords.Password.Created.AddDays(user.Passwords.Expiration.Days)) {
|
if (user.Passwords.Expiration.Enabled && DateTime.UtcNow > user.Passwords.Password.Created.AddDays(user.Passwords.Expiration.Days)) {
|
||||||
user.Passwords.Expired.Add(user.Passwords.Password.Prototype());
|
user.Passwords.Expired.Add(user.Passwords.Password.Prototype());
|
||||||
user.Passwords.Password = null;
|
|
||||||
|
|
||||||
return IDomainResult.Failed<string?>();
|
user.Passwords.Password = null;
|
||||||
|
user.Tokens = new List<Token>();
|
||||||
|
|
||||||
|
return IDomainResult.Failed<string?>("Password is expired, create new password.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creating JWT token
|
// Creating JWT token
|
||||||
@ -91,11 +101,15 @@ namespace WeatherForecast.Services {
|
|||||||
var token = _jwtService.CreateJwtToken(expires, claims);
|
var token = _jwtService.CreateJwtToken(expires, claims);
|
||||||
|
|
||||||
user.Tokens.Add(new Token {
|
user.Tokens.Add(new Token {
|
||||||
Value = token,
|
Value = AesService.EncryptString(_aesKey.IV, _aesKey.Key, token),
|
||||||
Created = created,
|
Created = created,
|
||||||
Expires = expires,
|
Expires = expires,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var (_, usdateUserResult) = _userDataProvider.Update(user);
|
||||||
|
if (!usdateUserResult.IsSuccess)
|
||||||
|
return IDomainResult.Failed<string?>();
|
||||||
|
|
||||||
return IDomainResult.Success(token);
|
return IDomainResult.Success(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,7 +118,12 @@ namespace WeatherForecast.Services {
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="token"></param>
|
/// <param name="token"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public IDomainResult Get(string token) {
|
public IDomainResult Get(string? token) {
|
||||||
|
if (_aesKey?.IV == null || _aesKey?.Key == null)
|
||||||
|
return IDomainResult.Failed("IV or Key are not set");
|
||||||
|
|
||||||
|
if (token == null)
|
||||||
|
return IDomainResult.Failed();
|
||||||
|
|
||||||
#region Retrieve user id from token claim
|
#region Retrieve user id from token claim
|
||||||
var (claims, getClaimsResult) = _jwtService.JwtTokenClaims(token);
|
var (claims, getClaimsResult) = _jwtService.JwtTokenClaims(token);
|
||||||
@ -116,17 +135,23 @@ namespace WeatherForecast.Services {
|
|||||||
return IDomainResult.Failed();
|
return IDomainResult.Failed();
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
var (user, getUserRersult) = _userDataProvider.Get(userId);
|
|
||||||
if(!getUserRersult.IsSuccess || user == null)
|
var (user, getUserResult) = _userDataProvider.Get(userId);
|
||||||
|
if (!getUserResult.IsSuccess || user == null)
|
||||||
return IDomainResult.Failed();
|
return IDomainResult.Failed();
|
||||||
|
|
||||||
// remove expired tokens
|
#region Tokens cleanup
|
||||||
user.Tokens = user.Tokens.Where(x => x.Expires < DateTime.UtcNow).ToList();
|
var userTokens = user.Tokens.Where(x => x.Expires > DateTime.UtcNow).ToList();
|
||||||
|
|
||||||
if (!user.Tokens.Any(x => x.Value == token))
|
if (user.Tokens.Count != userTokens.Count) {
|
||||||
return IDomainResult.Failed();
|
user.Tokens = userTokens;
|
||||||
|
_userDataProvider.Update(user);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
return IDomainResult.Success();
|
return userTokens.Select(x => AesService.DecryptString(_aesKey.IV, _aesKey.Key, x.Value)).Any(x => string.Compare(x, token) == 0)
|
||||||
|
? IDomainResult.Success()
|
||||||
|
: IDomainResult.Failed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
using DataProviders.Collections;
|
using DataProviders.Collections;
|
||||||
|
|
||||||
using HashService;
|
using CryptoProvider;
|
||||||
using JWTService;
|
using JWTService;
|
||||||
using WeatherForecast.Models.Requests;
|
using WeatherForecast.Models.Requests;
|
||||||
using Core.Abstractions;
|
using Core.Abstractions;
|
||||||
@ -27,7 +27,7 @@ namespace WeatherForecast.Services {
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class PasswordService : ServiceBase<PasswordService>, IPasswordService {
|
public class PasswordService : ServiceBase<PasswordService>, IPasswordService {
|
||||||
|
|
||||||
private readonly IHashService _hashService;
|
|
||||||
private readonly IUserDataProvider _userDataProvider;
|
private readonly IUserDataProvider _userDataProvider;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -39,11 +39,9 @@ namespace WeatherForecast.Services {
|
|||||||
/// <param name="userDataProvider"></param>
|
/// <param name="userDataProvider"></param>
|
||||||
public PasswordService(
|
public PasswordService(
|
||||||
ILogger<PasswordService> logger,
|
ILogger<PasswordService> logger,
|
||||||
IHashService hashService,
|
|
||||||
|
|
||||||
IUserDataProvider userDataProvider
|
IUserDataProvider userDataProvider
|
||||||
) : base(logger) {
|
) : base(logger) {
|
||||||
_hashService = hashService;
|
|
||||||
|
|
||||||
_userDataProvider = userDataProvider;
|
_userDataProvider = userDataProvider;
|
||||||
}
|
}
|
||||||
@ -58,7 +56,7 @@ namespace WeatherForecast.Services {
|
|||||||
try {
|
try {
|
||||||
|
|
||||||
|
|
||||||
var (salt, hash) = _hashService.CreateSaltedHash(requestData.Password);
|
var (salt, hash) = HashService.CreateSaltedHash(requestData.Password);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -9,8 +9,9 @@ using System.Text.Json.Serialization;
|
|||||||
using FileSecurityService.Extensions;
|
using FileSecurityService.Extensions;
|
||||||
using ImageProvider.Extensions;
|
using ImageProvider.Extensions;
|
||||||
using JWTService.Extensions;
|
using JWTService.Extensions;
|
||||||
using HashService.Extensions;
|
|
||||||
using Core.Middlewares;
|
using Core.Middlewares;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using WeatherForecast.Policies;
|
||||||
|
|
||||||
namespace WeatherForecast {
|
namespace WeatherForecast {
|
||||||
|
|
||||||
@ -75,6 +76,16 @@ namespace WeatherForecast {
|
|||||||
// https://docs.microsoft.com/en-us/aspnet/core/fundamentals/http-context?view=aspnetcore-3.1#use-httpcontext-from-custom-components
|
// https://docs.microsoft.com/en-us/aspnet/core/fundamentals/http-context?view=aspnetcore-3.1#use-httpcontext-from-custom-components
|
||||||
services.AddHttpContextAccessor();
|
services.AddHttpContextAccessor();
|
||||||
|
|
||||||
|
#region Policy Authorizations https://docs.microsoft.com/en-us/aspnet/core/security/authorization/policies?view=aspnetcore-6.0
|
||||||
|
services.AddScoped<IAuthorizationHandler, WhitelistTokenHandler>();
|
||||||
|
// services.AddScoped<IAuthorizationHandler, RecaptchaTokenHandler>();
|
||||||
|
|
||||||
|
services.AddAuthorization(options => {
|
||||||
|
options.AddPolicy("WhitelistToken", policy => policy.Requirements.Add(new WhitelistTokenRequirement()));
|
||||||
|
// options.AddPolicy("RecaptchaToken", policy => policy.Requirements.Add(new RecaptchaTokenRequirement("/swagger/index.html")));
|
||||||
|
});
|
||||||
|
#endregion
|
||||||
|
|
||||||
services.AddScoped<IContentService, ContentService>();
|
services.AddScoped<IContentService, ContentService>();
|
||||||
services.AddScoped<IShopItemService, ShopItemService>();
|
services.AddScoped<IShopItemService, ShopItemService>();
|
||||||
services.AddScoped<IShopItemsService, ShopItemsService>();
|
services.AddScoped<IShopItemsService, ShopItemsService>();
|
||||||
@ -96,7 +107,6 @@ namespace WeatherForecast {
|
|||||||
services.RegisterFileSecurityService();
|
services.RegisterFileSecurityService();
|
||||||
services.RegisterImageProvider();
|
services.RegisterImageProvider();
|
||||||
services.RegisterJWTService(appSettings);
|
services.RegisterJWTService(appSettings);
|
||||||
services.RegisterHashService();
|
|
||||||
|
|
||||||
#region Swagger
|
#region Swagger
|
||||||
services.ConfigureSwaggerGen(options => {
|
services.ConfigureSwaggerGen(options => {
|
||||||
|
|||||||
@ -14,24 +14,24 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="DomainResult" Version="3.0.0" />
|
<PackageReference Include="DomainResult" Version="3.0.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.5" />
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.10" />
|
||||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.14.0" />
|
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.17.0" />
|
||||||
<PackageReference Include="Serilog.Enrichers.Span" Version="2.3.0" />
|
<PackageReference Include="Serilog.Enrichers.Span" Version="2.3.0" />
|
||||||
<PackageReference Include="Serilog.Expressions" Version="3.4.0" />
|
<PackageReference Include="Serilog.Expressions" Version="3.4.1" />
|
||||||
<PackageReference Include="Serilog.Extensions.Hosting" Version="5.0.1" />
|
<PackageReference Include="Serilog.Extensions.Hosting" Version="5.0.1" />
|
||||||
<PackageReference Include="Serilog.Extensions.Logging" Version="3.1.0" />
|
<PackageReference Include="Serilog.Extensions.Logging" Version="3.1.0" />
|
||||||
<PackageReference Include="Serilog.Settings.Configuration" Version="3.3.0" />
|
<PackageReference Include="Serilog.Settings.Configuration" Version="3.4.0" />
|
||||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1" />
|
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Core\Core.csproj" />
|
<ProjectReference Include="..\Core\Core.csproj" />
|
||||||
|
<ProjectReference Include="..\CryptoProvider\CryptoProvider.csproj" />
|
||||||
<ProjectReference Include="..\DataProviders\DataProviders.csproj" />
|
<ProjectReference Include="..\DataProviders\DataProviders.csproj" />
|
||||||
<ProjectReference Include="..\Extensions\Extensions.csproj" />
|
<ProjectReference Include="..\Extensions\Extensions.csproj" />
|
||||||
|
<ProjectReference Include="..\ImageProvider\ImageProvider.csproj" />
|
||||||
<ProjectReference Include="..\Services\FileSecurityService\FileSecurityService.csproj" />
|
<ProjectReference Include="..\Services\FileSecurityService\FileSecurityService.csproj" />
|
||||||
<ProjectReference Include="..\Services\HashService\HashService.csproj" />
|
|
||||||
<ProjectReference Include="..\Services\ImageProvider\ImageProvider.csproj" />
|
|
||||||
<ProjectReference Include="..\Services\JWTService\JWTService.csproj" />
|
<ProjectReference Include="..\Services\JWTService\JWTService.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@ -20,6 +20,11 @@
|
|||||||
"Expires": "365"
|
"Expires": "365"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"JwtTokenEncryption": {
|
||||||
|
"IV": "2YJIwoV2C7QpgN8dquznmw==",
|
||||||
|
"Key": "KBsLNL2/pju3uX6Wtjkf2zUS1TbJ0YiD84zusIyPVUM="
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
"Database": {
|
"Database": {
|
||||||
"ConnectionString": "mongodb://root:example@mongo:27017"
|
"ConnectionString": "mongodb://root:example@mongo:27017"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user