mirror of
https://github.com/bitwarden/server.git
synced 2025-02-16 01:51:21 +01:00
Added redis caching libraries and implemented for user by id caching.
This commit is contained in:
parent
df94150848
commit
1ff49cd5b3
@ -18,6 +18,8 @@ using Bit.Core.Repositories;
|
|||||||
using Bit.Core.Services;
|
using Bit.Core.Services;
|
||||||
using Repos = Bit.Core.Repositories.SqlServer;
|
using Repos = Bit.Core.Repositories.SqlServer;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using StackExchange.Redis.Extensions.Core;
|
||||||
|
using StackExchange.Redis.Extensions.Protobuf;
|
||||||
//using Loggr.Extensions.Logging;
|
//using Loggr.Extensions.Logging;
|
||||||
|
|
||||||
namespace Bit.Api
|
namespace Bit.Api
|
||||||
@ -55,9 +57,16 @@ namespace Bit.Api
|
|||||||
ConfigurationBinder.Bind(Configuration.GetSection("GlobalSettings"), globalSettings);
|
ConfigurationBinder.Bind(Configuration.GetSection("GlobalSettings"), globalSettings);
|
||||||
services.AddSingleton(s => globalSettings);
|
services.AddSingleton(s => globalSettings);
|
||||||
|
|
||||||
|
// Caching
|
||||||
|
ISerializer serializer = new ProtobufSerializer();
|
||||||
|
services.AddSingleton(s => serializer);
|
||||||
|
ICacheClient cacheClient = new StackExchangeRedisCacheClient(serializer,
|
||||||
|
globalSettings.Cache.ConnectionString, globalSettings.Cache.Database);
|
||||||
|
services.AddSingleton(s => cacheClient);
|
||||||
|
|
||||||
// Repositories
|
// Repositories
|
||||||
services.AddSingleton<IUserRepository>(s => new Repos.UserRepository(globalSettings.SqlServer.ConnectionString));
|
services.AddSingleton<IUserRepository, Repos.UserRepository>();
|
||||||
services.AddSingleton<ICipherRepository>(s => new Repos.CipherRepository(globalSettings.SqlServer.ConnectionString));
|
services.AddSingleton<ICipherRepository, Repos.CipherRepository>();
|
||||||
|
|
||||||
// Context
|
// Context
|
||||||
services.AddScoped<CurrentContext>();
|
services.AddScoped<CurrentContext>();
|
||||||
|
@ -1,18 +1,22 @@
|
|||||||
{
|
{
|
||||||
"globalSettings": {
|
"globalSettings": {
|
||||||
"siteName": "bitwarden",
|
"siteName": "bitwarden",
|
||||||
"baseVaultUri": "http://localhost:4001",
|
"baseVaultUri": "http://localhost:4001",
|
||||||
"jwtSigningKey": "THIS IS A SECRET. IT KEEPS YOUR TOKEN SAFE. :)",
|
"jwtSigningKey": "THIS IS A SECRET. IT KEEPS YOUR TOKEN SAFE. :)",
|
||||||
"sqlServer": {
|
"sqlServer": {
|
||||||
"connectionString": "SECRET"
|
"connectionString": "SECRET"
|
||||||
},
|
},
|
||||||
"mail": {
|
"mail": {
|
||||||
"apiKey": "SECRET",
|
"apiKey": "SECRET",
|
||||||
"replyToEmail": "do-not-reply@bitwarden.com"
|
"replyToEmail": "do-not-reply@bitwarden.com"
|
||||||
},
|
},
|
||||||
"loggr": {
|
"loggr": {
|
||||||
"logKey": "SECRET",
|
"logKey": "SECRET",
|
||||||
"apiKey": "SECRET"
|
"apiKey": "SECRET"
|
||||||
}
|
},
|
||||||
|
"cache": {
|
||||||
|
"connectionString": "SECRET.COM:6380,password=SECRET,ssl=True,abortConnect=False",
|
||||||
|
"database": 0
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
7
src/Core/Constants.cs
Normal file
7
src/Core/Constants.cs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
namespace Bit.Core
|
||||||
|
{
|
||||||
|
public static class Constants
|
||||||
|
{
|
||||||
|
public const string UserIdCacheKey = "User:Id_{0}";
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using StackExchange.Redis.Extensions.Core.Configuration;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Bit.Core
|
namespace Bit.Core
|
||||||
@ -11,6 +12,7 @@ namespace Bit.Core
|
|||||||
public virtual SqlServerSettings SqlServer { get; set; } = new SqlServerSettings();
|
public virtual SqlServerSettings SqlServer { get; set; } = new SqlServerSettings();
|
||||||
public virtual MailSettings Mail { get; set; } = new MailSettings();
|
public virtual MailSettings Mail { get; set; } = new MailSettings();
|
||||||
public virtual LoggrSettings Loggr { get; set; } = new LoggrSettings();
|
public virtual LoggrSettings Loggr { get; set; } = new LoggrSettings();
|
||||||
|
public virtual CacheSettings Cache { get; set; } = new CacheSettings();
|
||||||
|
|
||||||
public class SqlServerSettings
|
public class SqlServerSettings
|
||||||
{
|
{
|
||||||
@ -28,5 +30,11 @@ namespace Bit.Core
|
|||||||
public string LogKey { get; set; }
|
public string LogKey { get; set; }
|
||||||
public string ApiKey { get; set; }
|
public string ApiKey { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class CacheSettings
|
||||||
|
{
|
||||||
|
public string ConnectionString { get; set; }
|
||||||
|
public int Database { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,6 @@ namespace Bit.Core.Repositories
|
|||||||
Task CreateAsync(T obj);
|
Task CreateAsync(T obj);
|
||||||
Task ReplaceAsync(T obj);
|
Task ReplaceAsync(T obj);
|
||||||
Task UpsertAsync(T obj);
|
Task UpsertAsync(T obj);
|
||||||
Task DeleteByIdAsync(TId id);
|
|
||||||
Task DeleteAsync(T obj);
|
Task DeleteAsync(T obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,15 +7,24 @@ using DataTableProxy;
|
|||||||
using Bit.Core.Domains;
|
using Bit.Core.Domains;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
using Dapper;
|
using Dapper;
|
||||||
|
using StackExchange.Redis.Extensions.Core;
|
||||||
|
|
||||||
namespace Bit.Core.Repositories.SqlServer
|
namespace Bit.Core.Repositories.SqlServer
|
||||||
{
|
{
|
||||||
public class CipherRepository : Repository<Cipher, Guid>, ICipherRepository
|
public class CipherRepository : Repository<Cipher, Guid>, ICipherRepository
|
||||||
{
|
{
|
||||||
public CipherRepository(string connectionString)
|
private readonly ICacheClient _cacheClient;
|
||||||
: base(connectionString)
|
|
||||||
|
public CipherRepository(GlobalSettings globalSettings, ICacheClient cacheClient)
|
||||||
|
: this(globalSettings.SqlServer.ConnectionString, cacheClient)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
public CipherRepository(string connectionString, ICacheClient cacheClient)
|
||||||
|
: base(connectionString)
|
||||||
|
{
|
||||||
|
_cacheClient = cacheClient;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<Cipher> GetByIdAsync(Guid id, Guid userId)
|
public async Task<Cipher> GetByIdAsync(Guid id, Guid userId)
|
||||||
{
|
{
|
||||||
var cipher = await GetByIdAsync(id);
|
var cipher = await GetByIdAsync(id);
|
||||||
@ -57,7 +66,7 @@ namespace Bit.Core.Repositories.SqlServer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Tuple<ICollection<Cipher>, ICollection<Guid>>>
|
public async Task<Tuple<ICollection<Cipher>, ICollection<Guid>>>
|
||||||
GetManySinceRevisionDateAndUserIdWithDeleteHistoryAsync(DateTime sinceRevisionDate, Guid userId)
|
GetManySinceRevisionDateAndUserIdWithDeleteHistoryAsync(DateTime sinceRevisionDate, Guid userId)
|
||||||
{
|
{
|
||||||
using(var connection = new SqlConnection(ConnectionString))
|
using(var connection = new SqlConnection(ConnectionString))
|
||||||
@ -78,11 +87,11 @@ namespace Bit.Core.Repositories.SqlServer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task UpdateUserEmailPasswordAndCiphersAsync(User user, IEnumerable<Cipher> ciphers)
|
public async Task UpdateUserEmailPasswordAndCiphersAsync(User user, IEnumerable<Cipher> ciphers)
|
||||||
{
|
{
|
||||||
if(ciphers.Count() == 0)
|
if(ciphers.Count() == 0)
|
||||||
{
|
{
|
||||||
return Task.FromResult(0);
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
using(var connection = new SqlConnection(ConnectionString))
|
using(var connection = new SqlConnection(ConnectionString))
|
||||||
@ -167,7 +176,8 @@ namespace Bit.Core.Repositories.SqlServer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Task.FromResult(0);
|
// Cleanup user cache
|
||||||
|
await _cacheClient.RemoveAllAsync(new string[] { string.Format(Constants.UserIdCacheKey, user.Id) });
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task CreateAsync(IEnumerable<Cipher> ciphers)
|
public Task CreateAsync(IEnumerable<Cipher> ciphers)
|
||||||
|
@ -75,17 +75,12 @@ namespace Bit.Core.Repositories.SqlServer
|
|||||||
}
|
}
|
||||||
|
|
||||||
public virtual async Task DeleteAsync(T obj)
|
public virtual async Task DeleteAsync(T obj)
|
||||||
{
|
|
||||||
await DeleteByIdAsync(obj.Id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual async Task DeleteByIdAsync(TId id)
|
|
||||||
{
|
{
|
||||||
using(var connection = new SqlConnection(ConnectionString))
|
using(var connection = new SqlConnection(ConnectionString))
|
||||||
{
|
{
|
||||||
await connection.ExecuteAsync(
|
await connection.ExecuteAsync(
|
||||||
$"[{Schema}].[{Table}_DeleteById]",
|
$"[{Schema}].[{Table}_DeleteById]",
|
||||||
new { Id = id },
|
new { Id = obj.Id },
|
||||||
commandType: CommandType.StoredProcedure);
|
commandType: CommandType.StoredProcedure);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,15 +5,39 @@ using System.Linq;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Bit.Core.Domains;
|
using Bit.Core.Domains;
|
||||||
using Dapper;
|
using Dapper;
|
||||||
|
using StackExchange.Redis.Extensions.Core;
|
||||||
|
|
||||||
namespace Bit.Core.Repositories.SqlServer
|
namespace Bit.Core.Repositories.SqlServer
|
||||||
{
|
{
|
||||||
public class UserRepository : Repository<User, Guid>, IUserRepository
|
public class UserRepository : Repository<User, Guid>, IUserRepository
|
||||||
{
|
{
|
||||||
public UserRepository(string connectionString)
|
private readonly ICacheClient _cacheClient;
|
||||||
: base(connectionString)
|
|
||||||
|
public UserRepository(GlobalSettings globalSettings, ICacheClient cacheClient)
|
||||||
|
: this(globalSettings.SqlServer.ConnectionString, cacheClient)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
public UserRepository(string connectionString, ICacheClient cacheClient)
|
||||||
|
: base(connectionString)
|
||||||
|
{
|
||||||
|
_cacheClient = cacheClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<User> GetByIdAsync(Guid id)
|
||||||
|
{
|
||||||
|
var cacheKey = string.Format(Constants.UserIdCacheKey, id);
|
||||||
|
|
||||||
|
var user = await _cacheClient.GetAsync<User>(cacheKey);
|
||||||
|
if(user != null)
|
||||||
|
{
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
user = await base.GetByIdAsync(id);
|
||||||
|
await _cacheClient.AddAsync(cacheKey, user);
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<User> GetByEmailAsync(string email)
|
public async Task<User> GetByEmailAsync(string email)
|
||||||
{
|
{
|
||||||
using(var connection = new SqlConnection(ConnectionString))
|
using(var connection = new SqlConnection(ConnectionString))
|
||||||
@ -26,5 +50,22 @@ namespace Bit.Core.Repositories.SqlServer
|
|||||||
return results.SingleOrDefault();
|
return results.SingleOrDefault();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override async Task ReplaceAsync(User user)
|
||||||
|
{
|
||||||
|
await base.ReplaceAsync(user);
|
||||||
|
await PurgeCacheAsync(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task DeleteAsync(User user)
|
||||||
|
{
|
||||||
|
await base.DeleteAsync(user);
|
||||||
|
await PurgeCacheAsync(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task PurgeCacheAsync(User user)
|
||||||
|
{
|
||||||
|
await _cacheClient.RemoveAllAsync(new string[] { string.Format(Constants.UserIdCacheKey, user.Id) });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,9 @@
|
|||||||
"Microsoft.AspNetCore.Mvc.Abstractions": "1.0.0-rc2-final",
|
"Microsoft.AspNetCore.Mvc.Abstractions": "1.0.0-rc2-final",
|
||||||
"Dapper": "1.42.0",
|
"Dapper": "1.42.0",
|
||||||
"DataTableProxy": "1.2.0",
|
"DataTableProxy": "1.2.0",
|
||||||
"Sendgrid": "6.3.4"
|
"Sendgrid": "6.3.4",
|
||||||
|
"StackExchange.Redis": "1.0.488",
|
||||||
|
"StackExchange.Redis.Extensions.Protobuf": "1.3.5"
|
||||||
},
|
},
|
||||||
|
|
||||||
"frameworks": {
|
"frameworks": {
|
||||||
|
Loading…
Reference in New Issue
Block a user