This commit is contained in:
JudahGabriel
2018-02-22 09:08:14 -06:00
14 changed files with 158 additions and 119 deletions
+1 -1
View File
@@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Text;
namespace RavenDB.Identity
namespace Raven.Identity
{
/// <summary>
/// The default implementation of <see cref="IdentityRole"/> which uses a string as the primary key.
+1 -1
View File
@@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Security.Claims;
using System.Text;
namespace RavenDB.Identity
namespace Raven.Identity
{
/// <summary>
/// Represents a claim that is granted to all users within a role.
+39 -1
View File
@@ -5,7 +5,7 @@ using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
namespace RavenDB.Identity
namespace Raven.Identity
{
/// <summary>
/// Base user class for RavenDB Identity. Inherit from this class to add your own properties.
@@ -112,25 +112,63 @@ namespace RavenDB.Identity
}
}
/// <summary>
/// Defines a user login.
/// </summary>
public sealed class IdentityUserLogin
{
/// <summary>
/// The ID of the login.
/// </summary>
public string Id { get; set; }
/// <summary>
/// The user ID.
/// </summary>
public string UserId { get; set; }
/// <summary>
/// The login provider.
/// </summary>
public string Provider { get; set; }
/// <summary>
/// The login provider key.
/// </summary>
public string ProviderKey { get; set; }
}
/// <summary>
/// A login claim.
/// </summary>
public class IdentityUserClaim
{
/// <summary>
/// The type of the login claim.
/// </summary>
public virtual string ClaimType { get; set; }
/// <summary>
/// The login claim value.
/// </summary>
public virtual string ClaimValue { get; set; }
}
/// <summary>
/// Entity that aides in helping us load users by a well-known name directly from the RavenDB ACID storage engine, bypassing the eventually consistent RavenDB indexes.
/// </summary>
public sealed class IdentityUserByUserName
{
/// <summary>
/// The ID of the user.
/// </summary>
public string UserId { get; set; }
/// <summary>
/// The user name.
/// </summary>
public string UserName { get; set; }
/// <summary>
/// Creates a new IdentityUserByUserName.
/// </summary>
/// <param name="userId"></param>
/// <param name="userName"></param>
public IdentityUserByUserName(string userId, string userName)
{
UserId = userId;
+3 -3
View File
@@ -18,14 +18,14 @@
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<Version>3.1.0</Version>
<Version>4.1.1</Version>
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Identity" Version="2.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Identity" Version="2.0.1" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.0.0" />
<PackageReference Include="RavenDB.Client" Version="3.5.5-patch-35218" />
<PackageReference Include="RavenDB.Client" Version="4.0.0" />
</ItemGroup>
</Project>
+3 -2
View File
@@ -1,5 +1,4 @@
using Microsoft.AspNetCore.Identity;
using Raven.Abstractions.Exceptions;
using Raven.Client;
using System;
using System.Collections.Generic;
@@ -10,8 +9,10 @@ using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Raven.Client.Documents.Session;
using Raven.Client.Exceptions;
namespace RavenDB.Identity
namespace Raven.Identity
{
/// <summary>
///
+66 -67
View File
@@ -1,81 +1,17 @@
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.DependencyInjection;
using Raven.Client;
using Raven.Client.Document;
using Raven.Client.Documents;
using Raven.Client.Documents.Session;
using System;
namespace RavenDB.Identity
namespace Raven.Identity
{
/// <summary>
/// Extends the <see cref="IServiceCollection"/> so that RavenDB services can be registered through it.
/// </summary>
public static class ServiceCollectionExtensions
{
/// <summary>
/// Registers a RavenDB <see cref="DocumentStore"/> as a singleton.
/// </summary>
/// <example>
/// <code>
/// public void ConfigureServices(IServiceCollection services)
/// {
/// services.AddRavenDb(Configuration.GetConnectionString("RavenDbConnection")));
/// }
/// </code>
/// </example>
/// <param name="serviceCollection"> The <see cref="IServiceCollection" /> to add services to. </param>
/// <param name="connectionString"> The connection string to the Raven database instance. </param>
/// <param name="configureAction">An optional action to configure the <see cref="IDocumentStore" />.</param>
/// <remarks>Based on code from https://github.com/maqduni/AspNetCore.Identity.RavenDb/blob/master/src/Maqduni.AspNetCore.Identity.RavenDb/RavenDbServiceCollectionExtensions.cs</remarks>
/// <returns>
/// The same service collection so that multiple calls can be chained.
/// </returns>
public static IServiceCollection AddRavenDb(
this IServiceCollection serviceCollection,
string connectionString,
Action<IDocumentStore> configureAction = null)
{
if (string.IsNullOrEmpty(connectionString))
{
throw new ArgumentNullException("Connection string cannot be null or empty.");
}
var documentStore = new DocumentStore();
documentStore.ParseConnectionString(connectionString);
documentStore.Conventions.RegisterIdConvention<IdentityUser>((dbname, commands, user) => "IdentityUsers/" + user.Id);
configureAction?.Invoke(documentStore);
documentStore.Initialize();
serviceCollection.AddSingleton<IDocumentStore>(documentStore);
return serviceCollection;
}
/// <summary>
/// Registers a RavenDB <see cref="IAsyncDocumentSession"/> to be created and disposed on each request.
/// </summary>
/// <example>
/// <code>
/// public void ConfigureServices(IServiceCollection services)
/// {
/// services.AddRavenDbAsyncSession();
/// }
/// </code>
/// </example>
/// <param name="serviceCollection"> The <see cref="IServiceCollection" /> to add services to. </param>
/// <remarks>Based on code from https://github.com/maqduni/AspNetCore.Identity.RavenDb/blob/master/src/Maqduni.AspNetCore.Identity.RavenDb/RavenDbServiceCollectionExtensions.cs</remarks>
/// <returns>The same service collection so that multiple calls can be chained.</returns>
public static IServiceCollection AddRavenDbAsyncSession(this IServiceCollection serviceCollection)
{
var docStore = serviceCollection.BuildServiceProvider().GetService<IDocumentStore>();
if (docStore == null)
{
throw new InvalidOperationException($"Please call {nameof(AddRavenDb)} before calling {nameof(AddRavenDbAsyncSession)}.");
}
serviceCollection.Add(new ServiceDescriptor(typeof(IAsyncDocumentSession), p => docStore.OpenAsyncSession(), ServiceLifetime.Scoped));
return serviceCollection;
}
/// <summary>
/// Registers a RavenDB as the user store.
/// </summary>
@@ -103,5 +39,68 @@ namespace RavenDB.Identity
return services;
}
/// <summary>
/// Registers a RavenDB <see cref="IAsyncDocumentSession"/> to be created and disposed on each request.
/// </summary>
/// <example>
/// <code>
/// public void ConfigureServices(IServiceCollection services)
/// {
/// services.AddRavenDbAsyncSession(() => myRavenDocStore);
/// }
/// </code>
/// </example>
/// <param name="serviceCollection"> The <see cref="IServiceCollection" /> to add services to. </param>
/// <param name="dbGetter">The function that gets the database.</param>
/// <remarks>Based on code from https://github.com/maqduni/AspNetCore.Identity.RavenDb/blob/master/src/Maqduni.AspNetCore.Identity.RavenDb/RavenDbServiceCollectionExtensions.cs</remarks>
/// <returns>The same service collection so that multiple calls can be chained.</returns>
public static IServiceCollection AddRavenDbAsyncSession(this IServiceCollection serviceCollection, Func<IDocumentStore> dbGetter)
{
serviceCollection.Add(new ServiceDescriptor(typeof(IAsyncDocumentSession), p => dbGetter().OpenAsyncSession(), ServiceLifetime.Scoped));
return serviceCollection;
}
/// <summary>
/// Registers a RavenDB <see cref="IAsyncDocumentSession"/> to be created and disposed on each request.
/// </summary>
/// <example>
/// <code>
/// public void ConfigureServices(IServiceCollection services)
/// {
/// services.AddRavenDbAsyncSession(() => myRavenDocStore);
/// }
/// </code>
/// </example>
/// <param name="serviceCollection"> The <see cref="IServiceCollection" /> to add services to. </param>
/// <param name="db">The RavenDB document store.</param>
/// <remarks>Based on code from https://github.com/maqduni/AspNetCore.Identity.RavenDb/blob/master/src/Maqduni.AspNetCore.Identity.RavenDb/RavenDbServiceCollectionExtensions.cs</remarks>
/// <returns>The same service collection so that multiple calls can be chained.</returns>
public static IServiceCollection AddRavenDbAsyncSession(this IServiceCollection serviceCollection, IDocumentStore db)
{
serviceCollection.Add(new ServiceDescriptor(typeof(IAsyncDocumentSession), p => db.OpenAsyncSession(), ServiceLifetime.Scoped));
return serviceCollection;
}
/// <summary>
/// Registers a RavenDB <see cref="IAsyncDocumentSession"/> to be created and disposed on each request.
/// This requires for an <see cref="IDocumentStore"/> to be added to dependency injection services.
/// </summary>
/// <example>
/// <code>
/// public void ConfigureServices(IServiceCollection services)
/// {
/// services.AddRavenDbAsyncSession();
/// }
/// </code>
/// </example>
/// <param name="serviceCollection"> The <see cref="IServiceCollection" /> to add services to. </param>
/// <remarks>Based on code from https://github.com/maqduni/AspNetCore.Identity.RavenDb/blob/master/src/Maqduni.AspNetCore.Identity.RavenDb/RavenDbServiceCollectionExtensions.cs</remarks>
/// <returns>The same service collection so that multiple calls can be chained.</returns>
public static IServiceCollection AddRavenDbAsyncSession(this IServiceCollection serviceCollection)
{
serviceCollection.Add(new ServiceDescriptor(typeof(IAsyncDocumentSession), p => p.GetRequiredService<IDocumentStore>().OpenAsyncSession(), ServiceLifetime.Scoped));
return serviceCollection;
}
}
}
+14 -14
View File
@@ -1,17 +1,14 @@
using System;
using System.Collections;
using Microsoft.AspNetCore.Identity;
using Raven.Client.Documents;
using Raven.Client.Documents.Session;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Raven.Client;
using System.Runtime.CompilerServices;
namespace RavenDB.Identity
namespace Raven.Identity
{
/// <summary>
/// UserStore for entities in a RavenDB database.
@@ -117,7 +114,7 @@ namespace RavenDB.Identity
if (string.IsNullOrEmpty(user.Id))
{
var conventions = DbSession.Advanced.DocumentStore.Conventions;
var entityName = conventions.GetTypeTagName(typeof(TUser));
var entityName = conventions.GetCollectionName(typeof(TUser));
var separator = conventions.IdentityPartsSeparator;
var id = $"{entityName}{separator}{user.Email}";
user.Id = id;
@@ -301,7 +298,7 @@ namespace RavenDB.Identity
}
/// <inheritdoc />
public Task<IList<TUser>> GetUsersForClaimAsync(Claim claim, CancellationToken cancellationToken)
public async Task<IList<TUser>> GetUsersForClaimAsync(Claim claim, CancellationToken cancellationToken)
{
ThrowIfDisposedOrCancelled(cancellationToken);
if (claim == null)
@@ -309,9 +306,10 @@ namespace RavenDB.Identity
throw new ArgumentNullException(nameof(claim));
}
return DbSession.Query<TUser>()
var list = await DbSession.Query<TUser>()
.Where(u => u.Claims.Any(c => c.ClaimType == claim.Type && c.ClaimValue == claim.Value))
.ToListAsync();
return list;
}
#endregion
@@ -380,7 +378,7 @@ namespace RavenDB.Identity
}
/// <inheritdoc />
public Task<IList<TUser>> GetUsersInRoleAsync(string roleName, CancellationToken cancellationToken)
public async Task<IList<TUser>> GetUsersInRoleAsync(string roleName, CancellationToken cancellationToken)
{
ThrowIfDisposedOrCancelled(cancellationToken);
if (string.IsNullOrEmpty(roleName))
@@ -388,10 +386,11 @@ namespace RavenDB.Identity
throw new ArgumentNullException(nameof(roleName));
}
return DbSession.Query<TUser>()
var users = await DbSession.Query<TUser>()
.Where(u => u.Roles.Contains(roleName, StringComparer.InvariantCultureIgnoreCase))
.Take(1024)
.ToListAsync();
return users;
}
#endregion
@@ -660,7 +659,8 @@ namespace RavenDB.Identity
if (_session == null)
{
_session = getSessionFunc();
_session.Advanced.DocumentStore.Conventions.RegisterIdConvention<IdentityUser>((dbname, commands, user) => "IdentityUsers/" + user.Id);
// TODO: do we really need this? I don't believe so. Brought over from Raven 3.x - the new 4.0 uses async version only.
//_session.Advanced.DocumentStore.Conventions.RegisterIdConvention<IdentityUser>((dbname, commands, user) => "IdentityUsers/" + user.Id);
}
return _session;
}
+1 -1
View File
@@ -5,7 +5,7 @@ using System.Security.Cryptography;
using System.Text;
using Microsoft.AspNetCore.Identity;
namespace RavenDB.Identity
namespace Raven.Identity
{
internal static class Util
{
+2 -3
View File
@@ -1,7 +1,7 @@
# ![RavenDB logo](https://github.com/JudahGabriel/RavenDB.Identity/blob/master/RavenDB.Identity/nuget-icon.png?raw=true) RavenDB.Identity #
RavenDB identity provider for ASP.NET Core.
The simple and easy Identity provider for RavenDB and ASP.NET Core. Use Raven to store your users and logins.
The simple and easy Identity provider for RavenDB and ASP.NET Core. Use Raven to store your users and logins. Uses RavenDB 4+
## Instructions ##
1. In Startup.cs:
@@ -11,8 +11,7 @@ public void ConfigureServices(IServiceCollection services)
{
// Add RavenDB and identity.
services
.AddRavenDb(Configuration.GetConnectionString("RavenDbConnection")) // Create a RavenDB DocumentStore singleton.
.AddRavenDbAsyncSession() // Create a RavenDB IAsyncDocumentSession for each request.
.AddRavenDbAsyncSession(docStore) // Create a RavenDB IAsyncDocumentSession for each request. docStore is your IDocumentStore instance.
.AddRavenDbIdentity<AppUser>(); // Use Raven for users and roles. AppUser is your class, a simple DTO to hold user data. See https://github.com/JudahGabriel/RavenDB.Identity/blob/master/Sample/Models/AppUser.cs
...
+5 -9
View File
@@ -1,19 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Raven.Client.Documents.Session;
using Sample.Models;
using Sample.Models.AccountViewModels;
using Sample.Services;
using Raven.Client;
using System;
using System.Security.Claims;
using System.Threading.Tasks;
namespace Sample.Controllers
{
+6 -8
View File
@@ -1,13 +1,11 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Raven.Client.Documents;
using Raven.Client.Documents.Session;
using Sample.Models;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Sample.Models;
using Raven.Client;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
namespace Sample.Controllers
{
+3 -5
View File
@@ -1,10 +1,8 @@
using Microsoft.AspNetCore.Mvc;
using Raven.Client;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Filters;
using Raven.Client.Documents.Session;
using System;
using System.Threading.Tasks;
namespace Sample.Controllers
{
+1 -1
View File
@@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using RavenDB.Identity;
using Raven.Identity;
namespace Sample.Models
{
+13 -3
View File
@@ -10,7 +10,8 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Sample.Models;
using Sample.Services;
using RavenDB.Identity;
using Raven.Identity;
using Raven.Client.Documents;
namespace Sample
{
@@ -26,10 +27,19 @@ namespace Sample
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Connect to a Raven server. We're using the public test playground at http://live-test.ravendb.net
// NOTE: Getting a DatabaseDoesNotExistException? Go to http://live-test.ravendb.net and create a database with the name 'Raven.Identity.Sample'
var docStore = new DocumentStore
{
Urls = new string[] { "http://live-test.ravendb.net" },
Database = "Raven.Identity.Sample"
};
docStore.Initialize();
// Add RavenDB and identity.
services
.AddRavenDb(Configuration.GetConnectionString("RavenDbConnection")) // Create a RavenDB DocumentStore singleton.
.AddRavenDbAsyncSession() // Create a RavenDB IAsyncDocumentSession for each request.
.AddRavenDbAsyncSession(docStore) // Create a RavenDB IAsyncDocumentSession for each request.
.AddRavenDbIdentity<AppUser>(); // Use Raven for users and roles.
// You can change the login path if need be.