A RavenDB *copy of the original EntityFramework user and role stores implementation. Use RavenDB to store your user and role entities. Covers most of the tests implemented by the official EntityFramework stores.
Why implementing another RavenDB store solution as there were at lest two more related projects at that point?
At the time this solution was implemented the other projects were not flexible enough for my requirements in terms of ID generation, how uniques are handled, direct injection of IAsyncDocumentSession, and extensibility overall as this project was required to be extensible to a multi-tenant store. (I am writing this document more than a year later so there may have been other reasons I don't remember any more).
- Support for [PersonalData]
attribute in terms of DB level encryption of properties annotated with the
[PersonalData]
attribute. - There is no implementation of the
UserOnly
store. If required use the provided user and roles stores and ignore roles related functionality.
1. CD into the solution directory
2. Start the RavenDB docker container (use flag -d to start in background)
$ docker-compose up
3. Run the sample project
$ dotnet run -p sample/Mcrio.AspNetCore.Identity.On.RavenDB.Sample/Mcrio.AspNetCore.Identity.On.RavenDB.Sample.csproj
4. Open in browser: https://localhost:5001
// RavenDB Studio is available at: http://localhost:32779
// If you want to try the Facebook login you need to provide
// the Facebook app id and secret in appsettings.json
Using the NuGet package manager install the Mcrio.AspNetCore.Identity.On.RavenDb package, or add the following line to the .csproj file:
<ItemGroup>
<PackageReference Include="Mcrio.AspNetCore.Identity.On.RavenDb"></PackageReference>
</ItemGroup>
Add the following lines to Startup.cs.
// ConfigureServices(...)
services
// Add identity by providing RavenDB stores related types
.AddIdentity<RavenIdentityUser, RavenIdentityRole>(
options =>
{
options.User.RequireUniqueEmail = true;
options.SignIn.RequireConfirmedEmail = false;
}
)
// Adds the RavenDB stores
.AddRavenDbStores<RavenUserStore, RavenRoleStore, RavenIdentityUser, RavenIdentityRole>(
// define how IAsyncDocumentSession is resolved from DI
// as library does NOT directly inject IAsyncDocumentSession
provider => provider.GetRequiredService<IAsyncDocumentSession>()
)
.AddDefaultUI()
.AddDefaultTokenProviders();
// Configure(...)
// - Put between UseRouting() and UseEndpoints()
// - Refer to official asp.net documentation for more details
app.UseAuthentication();
app.UseAuthorization();
Note: Use ASP.Identity UserManager
and RoleManager
to manipulate user and roles.
Mcrio.AspNetCore.Identity.On.RavenDb.Model.User.RavenIdentityUser
RavenDB ASP.Identity User.
Mcrio.AspNetCore.Identity.On.RavenDb.Model.Role.RavenIdentityRole
RavenDB ASP.Identity Role.
Mcrio.AspNetCore.Identity.On.RavenDb.Stores.RavenUserStore
RavenDB user store.
Mcrio.AspNetCore.Identity.On.RavenDb.Stores.RavenRoleStore
RavenDB role store.
Unique usernames are stores in the compare exchange.
When unique email is required it will be stored in the compare exchange to ensure uniqueness, otherwise there will be no compare exchange entry.
(*) Making the emails required at a later stage (when there already are users registered) is not recommended as the compare exchange will not have the existing emails registered. Technically it should work fine as ASP.Identity UserManager queries the emails before a new one is set, but uniqueness is not fully guaranteed as the compare exchange does not have existing emails and the RavenDB nodes are eventually consistent.
Id of User and Role can be changed after object construction.
By default set to null
which implies HiLo identifier generation.
Refer to official RavenDB document about identifier generation strategies.
Extend UserStore and RoleStore and override protected virtual CompareExchangeUtility CreateCompareExchangeUtility()
to return
an extended CompareExchangeUtility
that will override the functionality for generating
compare exchange key prefixes. See CompareExchangeUtility.GetKeyPrefix
for predefined compare exchange key prefixes.
- Extend
RavenIdentityUser
andRavenIdentityRole
to include aTenantId
property - Extend
UserStore
andRoleStore
that will:- Return an extended
CompareExchangeUtility
which includes the tenant identifier in the compare exchange prefixes. - Make sure tenant id is set on user and role creation.
- Return an extended
- RavenDB document store should register a
OnBeforeQuery
callback that will make sure theTenantId = ...
query condition is included in each query. - RavenDB document store should register a
OnAfterConversionToEntity
callback to make sure the document to be converted belongs to current tenant, otherwise throw an exception.
- 1.0.0 Stable version.
Nikola Josipović
This project is licensed under the MIT License. See License.md for more information.
addr1q87dhpq4wkm5gucymxkwcatu2et5enl9z8dal4c0fj98fxznraxyxtx5lf597gunnxn3tewwr6x2y588ttdkdlgaz79spp3avz
0xae0B28c1fCb707e1908706aAd65156b61aC6Ff0A