use IDocumentStore instead of IAsyncDocumentSession
This commit is contained in:
@@ -18,9 +18,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
||||
Readme.md = Readme.md
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample.RazorPages", "Samples\RazorPages\Sample.RazorPages.csproj", "{0C8F67DC-B6B3-4D8C-9E33-BBB47F858BE3}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sample.Mvc", "Samples\Mvc\Sample.Mvc.csproj", "{8AA88A38-C74A-4F0D-9853-EFA0D78F0E63}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample.Mvc", "Samples\Mvc\Sample.Mvc.csproj", "{8AA88A38-C74A-4F0D-9853-EFA0D78F0E63}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
@@ -32,10 +30,6 @@ Global
|
||||
{C7824FBF-9E9B-40B5-9CF5-4884F8378BA6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C7824FBF-9E9B-40B5-9CF5-4884F8378BA6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C7824FBF-9E9B-40B5-9CF5-4884F8378BA6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0C8F67DC-B6B3-4D8C-9E33-BBB47F858BE3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0C8F67DC-B6B3-4D8C-9E33-BBB47F858BE3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0C8F67DC-B6B3-4D8C-9E33-BBB47F858BE3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0C8F67DC-B6B3-4D8C-9E33-BBB47F858BE3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8AA88A38-C74A-4F0D-9853-EFA0D78F0E63}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8AA88A38-C74A-4F0D-9853-EFA0D78F0E63}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8AA88A38-C74A-4F0D-9853-EFA0D78F0E63}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.2.0" />
|
||||
<PackageReference Include="RavenDB.Client" Version="4.2.0" />
|
||||
<PackageReference Include="RavenDB.DependencyInjection" Version="3.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Raven.Client;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Raven.Client.Documents;
|
||||
using Raven.Client.Documents.Session;
|
||||
using Raven.Client.Exceptions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Raven.Client.Documents.Session;
|
||||
using Raven.Client.Exceptions;
|
||||
using Raven.Client.Documents;
|
||||
|
||||
namespace Raven.Identity
|
||||
{
|
||||
@@ -47,9 +45,9 @@ namespace Raven.Identity
|
||||
/// <summary>
|
||||
/// Constructs a new instance of <see cref="RoleStore{TRole}"/>.
|
||||
/// </summary>
|
||||
/// <param name="context">The <see cref="IAsyncDocumentSession"/>.</param>
|
||||
/// <param name="store">The <see cref="IDocumentStore"/>.</param>
|
||||
/// <param name="describer">The <see cref="IdentityErrorDescriber"/>.</param>
|
||||
public RoleStore(IAsyncDocumentSession context, IdentityErrorDescriber describer = null) : base(context, describer) { }
|
||||
public RoleStore(IDocumentStore store, IdentityErrorDescriber describer = null) : base(store, describer) { }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a entity representing a role claim.
|
||||
@@ -76,11 +74,11 @@ namespace Raven.Identity
|
||||
/// <summary>
|
||||
/// Constructs a new instance of <see cref="RoleStore{TRole, TRoleClaim}"/>.
|
||||
/// </summary>
|
||||
/// <param name="context">The <see cref="IAsyncDocumentSession"/>.</param>
|
||||
/// <param name="store">The <see cref="IDocumentStore"/>.</param>
|
||||
/// <param name="describer">The <see cref="IdentityErrorDescriber"/>.</param>
|
||||
public RoleStore(IAsyncDocumentSession context, IdentityErrorDescriber describer = null)
|
||||
public RoleStore(IDocumentStore store, IdentityErrorDescriber describer = null)
|
||||
{
|
||||
AsyncSession = context ?? throw new ArgumentNullException(nameof(context));
|
||||
Store = store ?? throw new ArgumentNullException(nameof(store));
|
||||
ErrorDescriber = describer ?? new IdentityErrorDescriber();
|
||||
}
|
||||
|
||||
@@ -90,32 +88,13 @@ namespace Raven.Identity
|
||||
/// <summary>
|
||||
/// Gets the database context for this store.
|
||||
/// </summary>
|
||||
public IAsyncDocumentSession AsyncSession { get; private set; }
|
||||
public IDocumentStore Store { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="IdentityErrorDescriber"/> for any error that occurred with the current operation.
|
||||
/// </summary>
|
||||
public IdentityErrorDescriber ErrorDescriber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a flag indicating if changes should be persisted after CreateAsync, UpdateAsync and DeleteAsync are called.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// True if changes should be automatically persisted, otherwise false.
|
||||
/// </value>
|
||||
public bool AutoSaveChanges { get; set; } = true;
|
||||
|
||||
/// <summary>Saves the current store.</summary>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
|
||||
/// <returns>The <see cref="Task"/> that represents the asynchronous operation.</returns>
|
||||
private async Task SaveChanges(CancellationToken cancellationToken)
|
||||
{
|
||||
if (AutoSaveChanges)
|
||||
{
|
||||
await AsyncSession.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new role in a store as an asynchronous operation.
|
||||
/// </summary>
|
||||
@@ -135,9 +114,12 @@ namespace Raven.Identity
|
||||
throw new ArgumentNullException(nameof(role.Name));
|
||||
}
|
||||
|
||||
var roleId = GetRavenIdFromRoleName(role.Name, AsyncSession.Advanced.DocumentStore);
|
||||
await AsyncSession.StoreAsync(role, roleId);
|
||||
await SaveChanges(cancellationToken);
|
||||
using (IAsyncDocumentSession session = Store.OpenAsyncSession())
|
||||
{
|
||||
var roleId = GetRavenIdFromRoleName(role.Name, Store);
|
||||
await session.StoreAsync(role, roleId);
|
||||
await session.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
return IdentityResult.Success;
|
||||
}
|
||||
|
||||
@@ -161,7 +143,10 @@ namespace Raven.Identity
|
||||
//role.ConcurrencyStamp = Guid.NewGuid().ToString();
|
||||
try
|
||||
{
|
||||
await SaveChanges(cancellationToken);
|
||||
using (IAsyncDocumentSession session = Store.OpenAsyncSession())
|
||||
{
|
||||
await session.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
catch (ConcurrencyException)
|
||||
{
|
||||
@@ -184,10 +169,18 @@ namespace Raven.Identity
|
||||
{
|
||||
throw new ArgumentNullException(nameof(role));
|
||||
}
|
||||
AsyncSession.Delete(role.Id);
|
||||
|
||||
using (IAsyncDocumentSession session = Store.OpenAsyncSession())
|
||||
{
|
||||
session.Delete(role.Id);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await SaveChanges(cancellationToken);
|
||||
using (IAsyncDocumentSession session = Store.OpenAsyncSession())
|
||||
{
|
||||
await session.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
catch (ConcurrencyException)
|
||||
{
|
||||
@@ -259,7 +252,11 @@ namespace Raven.Identity
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
ThrowIfDisposed();
|
||||
return AsyncSession.LoadAsync<TRole>(id, cancellationToken);
|
||||
|
||||
using (IAsyncDocumentSession session = Store.OpenAsyncSession())
|
||||
{
|
||||
return session.LoadAsync<TRole>(id, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -273,8 +270,11 @@ namespace Raven.Identity
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
ThrowIfDisposed();
|
||||
|
||||
var roleId = GetRavenIdFromRoleName(normalizedName, AsyncSession.Advanced.DocumentStore);
|
||||
return AsyncSession.LoadAsync<TRole>(roleId);
|
||||
using (IAsyncDocumentSession session = Store.OpenAsyncSession())
|
||||
{
|
||||
var roleId = GetRavenIdFromRoleName(normalizedName, Store);
|
||||
return session.LoadAsync<TRole>(roleId);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Raven.Client;
|
||||
using Raven.Client.Documents;
|
||||
using Raven.Client.Documents.Session;
|
||||
using System;
|
||||
|
||||
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 as the user store.
|
||||
/// </summary>
|
||||
/// <typeparam name="TUser">The type of user. This should be a class you created derived from <see cref="IdentityUser"/>.</typeparam>
|
||||
/// <param name="services"></param>
|
||||
/// <param name="setupAction">Identity options configuration.</param>
|
||||
/// <returns>The identity builder.</returns>
|
||||
public static IdentityBuilder AddRavenDbIdentity<TUser>(this IServiceCollection services, Action<IdentityOptions> setupAction = null)
|
||||
where TUser : IdentityUser
|
||||
{
|
||||
return AddRavenDbIdentity<TUser, IdentityRole>(services, setupAction);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers a RavenDB as the user store.
|
||||
/// </summary>
|
||||
/// <typeparam name="TUser">The type of user. This should be a class you created derived from <see cref="IdentityUser"/>.</typeparam>
|
||||
/// <typeparam name="TRole">The type of role. This should be a class you created derived from <see cref="IdentityRole"/>.</typeparam>
|
||||
/// <param name="services"></param>
|
||||
/// <param name="setupAction">Identity options configuration.</param>
|
||||
/// <returns>The identity builder.</returns>
|
||||
public static IdentityBuilder AddRavenDbIdentity<TUser, TRole>(this IServiceCollection services, Action<IdentityOptions> setupAction = null)
|
||||
where TUser : IdentityUser
|
||||
where TRole : IdentityRole, new()
|
||||
{
|
||||
// Add the AspNet identity system to work with our RavenDB identity objects.
|
||||
IdentityBuilder identityBuilder;
|
||||
if (setupAction != null)
|
||||
{
|
||||
identityBuilder = services.AddIdentity<TUser, TRole>(setupAction)
|
||||
.AddDefaultTokenProviders();
|
||||
}
|
||||
else
|
||||
{
|
||||
identityBuilder = services.AddIdentity<TUser, TRole>()
|
||||
.AddDefaultTokenProviders();
|
||||
}
|
||||
|
||||
services.AddScoped<Microsoft.AspNetCore.Identity.IUserStore<TUser>, UserStore<TUser, TRole>>();
|
||||
services.AddScoped<Microsoft.AspNetCore.Identity.IRoleStore<TRole>, RoleStore<TRole>>();
|
||||
|
||||
return identityBuilder;
|
||||
}
|
||||
}
|
||||
}
|
||||
+94
-107
@@ -1,6 +1,5 @@
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Raven.Client.Documents;
|
||||
using Raven.Client.Documents.Operations;
|
||||
using Raven.Client.Documents.Operations.CompareExchange;
|
||||
using Raven.Client.Documents.Session;
|
||||
using System;
|
||||
@@ -36,27 +35,17 @@ namespace Raven.Identity
|
||||
where TRole : IdentityRole, new()
|
||||
{
|
||||
private bool _disposed;
|
||||
private readonly Func<IAsyncDocumentSession> getSessionFunc;
|
||||
private IAsyncDocumentSession _session;
|
||||
private IDocumentStore _store;
|
||||
|
||||
private const string emailReservationKeyPrefix = "emails/";
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new user store that uses the Raven document session returned from the specified session fetcher.
|
||||
/// Creates a new user store that uses the specified Raven document store.
|
||||
/// </summary>
|
||||
/// <param name="getSession">The function that gets the Raven document session.</param>
|
||||
public UserStore(Func<IAsyncDocumentSession> getSession)
|
||||
/// <param name="store"></param>
|
||||
public UserStore(IDocumentStore store)
|
||||
{
|
||||
this.getSessionFunc = getSession;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new user store that uses the specified Raven document session.
|
||||
/// </summary>
|
||||
/// <param name="session"></param>
|
||||
public UserStore(IAsyncDocumentSession session)
|
||||
{
|
||||
this._session = session;
|
||||
this._store = store;
|
||||
}
|
||||
|
||||
#region IDispoable implementation
|
||||
@@ -129,7 +118,7 @@ namespace Raven.Identity
|
||||
|
||||
if (string.IsNullOrEmpty(user.Id))
|
||||
{
|
||||
var conventions = DbSession.Advanced.DocumentStore.Conventions;
|
||||
var conventions = _store.Conventions;
|
||||
var entityName = conventions.GetCollectionName(typeof(TUser));
|
||||
var prefix = conventions.TransformTypeCollectionNameToDocumentIdPrefix(entityName);
|
||||
var separator = conventions.IdentityPartsSeparator;
|
||||
@@ -152,7 +141,7 @@ namespace Raven.Identity
|
||||
// Note: This operation takes place outside of the session transaction it is a cluster-wide reservation.
|
||||
var compareExchangeKey = GetCompareExchangeKeyFromEmail(user.Email);
|
||||
var reserveEmailOperation = new PutCompareExchangeValueOperation<string>(compareExchangeKey, user.Id, 0);
|
||||
var reserveEmailResult = await DbSession.Advanced.DocumentStore.Operations.SendAsync(reserveEmailOperation);
|
||||
var reserveEmailResult = await _store.Operations.SendAsync(reserveEmailOperation);
|
||||
if (!reserveEmailResult.Successful)
|
||||
{
|
||||
return IdentityResult.Failed(new[]
|
||||
@@ -165,15 +154,17 @@ namespace Raven.Identity
|
||||
});
|
||||
}
|
||||
|
||||
using (IAsyncDocumentSession session = _store.OpenAsyncSession())
|
||||
{
|
||||
// This model allows us to lookup a user by name in order to get the id
|
||||
await DbSession.StoreAsync(user, cancellationToken);
|
||||
await session.StoreAsync(user, cancellationToken);
|
||||
|
||||
// Because this a a cluster-wide operation due to compare/exchange tokens,
|
||||
// we need to save changes here; if we can't store the user,
|
||||
// we need to roll back the email reservation.
|
||||
try
|
||||
{
|
||||
await DbSession.SaveChangesAsync();
|
||||
await session.SaveChangesAsync();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
@@ -182,6 +173,7 @@ namespace Raven.Identity
|
||||
await this.DeleteUserEmailReservation(user.Email);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
return IdentityResult.Success;
|
||||
}
|
||||
@@ -214,10 +206,14 @@ namespace Raven.Identity
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Delete the user and save it. We must save it because deleting is a cluster-wide operation.
|
||||
// Only if the deletion succeeds will we remove the cluseter-wide compare/exchange key.
|
||||
this.DbSession.Delete(user);
|
||||
await this.DbSession.SaveChangesAsync();
|
||||
using (IAsyncDocumentSession session = _store.OpenAsyncSession())
|
||||
{
|
||||
session.Delete(user);
|
||||
await session.SaveChangesAsync();
|
||||
}
|
||||
|
||||
return IdentityResult.Success;
|
||||
}
|
||||
@@ -227,7 +223,10 @@ namespace Raven.Identity
|
||||
{
|
||||
ThrowIfDisposedOrCancelled(cancellationToken);
|
||||
|
||||
return DbSession.LoadAsync<TUser>(userId);
|
||||
using (IAsyncDocumentSession session = _store.OpenAsyncSession())
|
||||
{
|
||||
return session.LoadAsync<TUser>(userId);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -241,7 +240,8 @@ namespace Raven.Identity
|
||||
|
||||
var compareExchangeKey = GetCompareExchangeKeyFromEmail(normalizedUserName);
|
||||
var getEmailReservationOperation = new GetCompareExchangeValueOperation<string>(compareExchangeKey);
|
||||
var emailReservationResultOrNull = await DbSession.Advanced.DocumentStore.Operations.SendAsync(getEmailReservationOperation);
|
||||
|
||||
var emailReservationResultOrNull = await _store.Operations.SendAsync(getEmailReservationOperation);
|
||||
var userId = emailReservationResultOrNull?.Value;
|
||||
if (string.IsNullOrEmpty(userId))
|
||||
{
|
||||
@@ -277,7 +277,11 @@ namespace Raven.Identity
|
||||
Provider = login.LoginProvider,
|
||||
ProviderKey = login.ProviderKey
|
||||
};
|
||||
await DbSession.StoreAsync(userLogin);
|
||||
|
||||
using (IAsyncDocumentSession session = _store.OpenAsyncSession())
|
||||
{
|
||||
await session.StoreAsync(userLogin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -288,10 +292,14 @@ namespace Raven.Identity
|
||||
|
||||
var login = new UserLoginInfo(loginProvider, providerKey, string.Empty);
|
||||
string loginId = Util.GetLoginId(login);
|
||||
var loginDoc = await DbSession.LoadAsync<IdentityUserLogin>(loginId);
|
||||
|
||||
using (IAsyncDocumentSession session = _store.OpenAsyncSession())
|
||||
{
|
||||
var loginDoc = await session.LoadAsync<IdentityUserLogin>(loginId);
|
||||
if (loginDoc != null)
|
||||
{
|
||||
DbSession.Delete(loginDoc);
|
||||
session.Delete(loginDoc);
|
||||
}
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
@@ -312,10 +320,14 @@ namespace Raven.Identity
|
||||
{
|
||||
var login = new UserLoginInfo(loginProvider, providerKey, string.Empty);
|
||||
string loginId = Util.GetLoginId(login);
|
||||
var loginDoc = await DbSession.LoadAsync<IdentityUserLogin>(loginId);
|
||||
|
||||
using (IAsyncDocumentSession session = _store.OpenAsyncSession())
|
||||
{
|
||||
var loginDoc = await session.LoadAsync<IdentityUserLogin>(loginId);
|
||||
if (loginDoc != null)
|
||||
{
|
||||
return await DbSession.LoadAsync<TUser>(loginDoc.UserId);
|
||||
return await session.LoadAsync<TUser>(loginDoc.UserId);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -376,10 +388,12 @@ namespace Raven.Identity
|
||||
throw new ArgumentNullException(nameof(claim));
|
||||
}
|
||||
|
||||
var list = await DbSession.Query<TUser>()
|
||||
using (IAsyncDocumentSession session = _store.OpenAsyncSession())
|
||||
{
|
||||
return await session.Query<TUser>()
|
||||
.Where(u => u.Claims.Any(c => c.ClaimType == claim.Type && c.ClaimValue == claim.Value))
|
||||
.ToListAsync();
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -392,18 +406,21 @@ namespace Raven.Identity
|
||||
ThrowIfNullDisposedCancelled(user, cancellationToken);
|
||||
|
||||
// See if we have an IdentityRole with that name.
|
||||
var identityUserCollection = DbSession.Advanced.DocumentStore.Conventions.GetCollectionName(typeof(TRole));
|
||||
var prefix = DbSession.Advanced.DocumentStore.Conventions.TransformTypeCollectionNameToDocumentIdPrefix(identityUserCollection);
|
||||
var identityPartSeperator = DbSession.Advanced.DocumentStore.Conventions.IdentityPartsSeparator;
|
||||
var identityUserCollection = _store.Conventions.GetCollectionName(typeof(TRole));
|
||||
var prefix = _store.Conventions.TransformTypeCollectionNameToDocumentIdPrefix(identityUserCollection);
|
||||
var identityPartSeperator = _store.Conventions.IdentityPartsSeparator;
|
||||
var roleNameLowered = roleName.ToLowerInvariant();
|
||||
var roleId = prefix + identityPartSeperator + roleNameLowered;
|
||||
var existingRoleOrNull = await this.DbSession.LoadAsync<IdentityRole>(roleId, cancellationToken);
|
||||
|
||||
using (IAsyncDocumentSession session = _store.OpenAsyncSession())
|
||||
{
|
||||
var existingRoleOrNull = await session.LoadAsync<IdentityRole>(roleId, cancellationToken);
|
||||
if (existingRoleOrNull == null)
|
||||
{
|
||||
ThrowIfDisposedOrCancelled(cancellationToken);
|
||||
existingRoleOrNull = new TRole();
|
||||
existingRoleOrNull.Name = roleNameLowered;
|
||||
await this.DbSession.StoreAsync(existingRoleOrNull, roleId, cancellationToken);
|
||||
await session.StoreAsync(existingRoleOrNull, roleId, cancellationToken);
|
||||
}
|
||||
|
||||
// Use the real name (not normalized/uppered/lowered) of the role, as specified by the user.
|
||||
@@ -418,6 +435,7 @@ namespace Raven.Identity
|
||||
existingRoleOrNull.Users.Add(user.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task RemoveFromRoleAsync(TUser user, string roleName, CancellationToken cancellationToken)
|
||||
@@ -426,13 +444,17 @@ namespace Raven.Identity
|
||||
|
||||
user.GetRolesList().RemoveAll(r => string.Equals(r, roleName, StringComparison.InvariantCultureIgnoreCase));
|
||||
|
||||
var roleId = RoleStore<TRole>.GetRavenIdFromRoleName(roleName, DbSession.Advanced.DocumentStore);
|
||||
var roleOrNull = await DbSession.LoadAsync<IdentityRole>(roleId, cancellationToken);
|
||||
var roleId = RoleStore<TRole>.GetRavenIdFromRoleName(roleName, _store);
|
||||
|
||||
using (IAsyncDocumentSession session = _store.OpenAsyncSession())
|
||||
{
|
||||
var roleOrNull = await session.LoadAsync<IdentityRole>(roleId, cancellationToken);
|
||||
if (roleOrNull != null)
|
||||
{
|
||||
roleOrNull.Users.Remove(user.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<IList<string>> GetRolesAsync(TUser user, CancellationToken cancellationToken)
|
||||
@@ -462,11 +484,13 @@ namespace Raven.Identity
|
||||
throw new ArgumentNullException(nameof(roleName));
|
||||
}
|
||||
|
||||
var users = await DbSession.Query<TUser>()
|
||||
using (IAsyncDocumentSession session = _store.OpenAsyncSession())
|
||||
{
|
||||
return await session.Query<TUser>()
|
||||
.Where(u => u.Roles.Contains(roleName, StringComparer.InvariantCultureIgnoreCase))
|
||||
.Take(1024)
|
||||
.ToListAsync();
|
||||
return users;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -561,9 +585,12 @@ namespace Raven.Identity
|
||||
{
|
||||
ThrowIfDisposedOrCancelled(cancellationToken);
|
||||
|
||||
return DbSession.Query<TUser>()
|
||||
using (IAsyncDocumentSession session = _store.OpenAsyncSession())
|
||||
{
|
||||
return session.Query<TUser>()
|
||||
.FirstOrDefaultAsync(u => u.Email == normalizedEmail, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<string> GetNormalizedEmailAsync(TUser user, CancellationToken cancellationToken)
|
||||
@@ -733,10 +760,12 @@ namespace Raven.Identity
|
||||
/// <inheritdoc />
|
||||
public async Task SetTokenAsync(TUser user, string loginProvider, string name, string value, CancellationToken cancellationToken)
|
||||
{
|
||||
var id = IdentityUserAuthToken.GetWellKnownId(DbSession.Advanced.DocumentStore, user.Id, loginProvider, name);
|
||||
var id = IdentityUserAuthToken.GetWellKnownId(_store, user.Id, loginProvider, name);
|
||||
ThrowIfDisposedOrCancelled(cancellationToken);
|
||||
|
||||
var existingOrNull = await DbSession.LoadAsync<IdentityUserAuthToken>(id);
|
||||
using (IAsyncDocumentSession session = _store.OpenAsyncSession())
|
||||
{
|
||||
var existingOrNull = await session.LoadAsync<IdentityUserAuthToken>(id);
|
||||
if (existingOrNull == null)
|
||||
{
|
||||
existingOrNull = new IdentityUserAuthToken
|
||||
@@ -747,17 +776,22 @@ namespace Raven.Identity
|
||||
UserId = user.Id,
|
||||
Value = value
|
||||
};
|
||||
await DbSession.StoreAsync(existingOrNull);
|
||||
await session.StoreAsync(existingOrNull);
|
||||
}
|
||||
|
||||
existingOrNull.Value = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task RemoveTokenAsync(TUser user, string loginProvider, string name, CancellationToken cancellationToken)
|
||||
{
|
||||
var id = IdentityUserAuthToken.GetWellKnownId(DbSession.Advanced.DocumentStore, user.Id, loginProvider, name);
|
||||
DbSession.Delete(id);
|
||||
var id = IdentityUserAuthToken.GetWellKnownId(_store, user.Id, loginProvider, name);
|
||||
|
||||
using (IAsyncDocumentSession session = _store.OpenAsyncSession())
|
||||
{
|
||||
session.Delete(id);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
@@ -765,8 +799,11 @@ namespace Raven.Identity
|
||||
/// <inheritdoc />
|
||||
public async Task<string> GetTokenAsync(TUser user, string loginProvider, string name, CancellationToken cancellationToken)
|
||||
{
|
||||
var id = IdentityUserAuthToken.GetWellKnownId(DbSession.Advanced.DocumentStore, user.Id, loginProvider, name);
|
||||
var tokenOrNull = await DbSession.LoadAsync<IdentityUserAuthToken>(id);
|
||||
var id = IdentityUserAuthToken.GetWellKnownId(_store, user.Id, loginProvider, name);
|
||||
|
||||
using (IAsyncDocumentSession session = _store.OpenAsyncSession())
|
||||
{
|
||||
var tokenOrNull = await session.LoadAsync<IdentityUserAuthToken>(id);
|
||||
if (tokenOrNull == null)
|
||||
{
|
||||
return null;
|
||||
@@ -774,6 +811,7 @@ namespace Raven.Identity
|
||||
|
||||
return tokenOrNull.Value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task ReplaceCodesAsync(TUser user, IEnumerable<string> recoveryCodes, CancellationToken cancellationToken)
|
||||
@@ -801,69 +839,18 @@ namespace Raven.Identity
|
||||
/// <summary>
|
||||
/// Gets the users as an IQueryable.
|
||||
/// </summary>
|
||||
public IQueryable<TUser> Users => this.DbSession.Query<TUser>();
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Migrates the data model from a previous version of the RavenDB.Identity framework to the v6 model.
|
||||
/// This is necessary if you stored users using an RavenDB.Identity version 5 or ealier.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static void MigrateToV6(IDocumentStore docStore)
|
||||
{
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
var collectionName = docStore.Conventions.FindCollectionName(typeof(IdentityUserByUserName));
|
||||
|
||||
// Step 1: find all the old IdentityByUserName objects.
|
||||
var emails = new List<(string userId, string email)>(1000);
|
||||
using (var dbSession = docStore.OpenSession())
|
||||
{
|
||||
var stream = dbSession.Advanced.Stream<IdentityUserByUserName>($"{collectionName}/");
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
while (stream.MoveNext())
|
||||
{
|
||||
var doc = stream.Current.Document;
|
||||
emails.Add((userId: doc.UserId, email: doc.UserName));
|
||||
}
|
||||
}
|
||||
|
||||
// Step 2: store each email as a cluster-wide compare/exchange value.
|
||||
foreach (var (userId, email) in emails)
|
||||
{
|
||||
var compareExchangeKey = GetCompareExchangeKeyFromEmail(email);
|
||||
var storeOperation = new PutCompareExchangeValueOperation<string>(compareExchangeKey, userId, 0);
|
||||
var storeResult = docStore.Operations.Send(storeOperation);
|
||||
if (!storeResult.Successful)
|
||||
{
|
||||
var exception = new Exception($"Unable to migrate to RavenDB.Identity V6. An error occurred while storing the compare/exchange value. Before running this {nameof(MigrateToV6)} again, please delete all compare/exchange values in Raven that begin with {emailReservationKeyPrefix}.");
|
||||
exception.Data.Add("compareExchangeKey", compareExchangeKey);
|
||||
exception.Data.Add("compareExchangeValue", userId);
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
|
||||
// Step 3: remove all IdentityUserByUserName objects.
|
||||
var operation = docStore
|
||||
.Operations
|
||||
.Send(new DeleteByQueryOperation(new Client.Documents.Queries.IndexQuery
|
||||
{
|
||||
Query = $"from {collectionName}"
|
||||
}));
|
||||
operation.WaitForCompletion();
|
||||
}
|
||||
|
||||
private IAsyncDocumentSession DbSession
|
||||
public IQueryable<TUser> Users
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_session == null)
|
||||
using (IAsyncDocumentSession session = _store.OpenAsyncSession())
|
||||
{
|
||||
_session = getSessionFunc();
|
||||
}
|
||||
return _session;
|
||||
return session.Query<TUser>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private void ThrowIfNullDisposedCancelled(TUser user, CancellationToken token)
|
||||
{
|
||||
@@ -890,7 +877,7 @@ namespace Raven.Identity
|
||||
private Task<CompareExchangeResult<string>> DeleteUserEmailReservation(string email)
|
||||
{
|
||||
var key = GetCompareExchangeKeyFromEmail(email);
|
||||
var store = DbSession.Advanced.DocumentStore;
|
||||
var store = _store;
|
||||
|
||||
var readResult = store.Operations.Send(new GetCompareExchangeValueOperation<string>(key));
|
||||
if (readResult == null)
|
||||
@@ -899,7 +886,7 @@ namespace Raven.Identity
|
||||
}
|
||||
|
||||
var deleteEmailOperation = new DeleteCompareExchangeValueOperation<string>(key, readResult.Index);
|
||||
return DbSession.Advanced.DocumentStore.Operations.SendAsync(deleteEmailOperation);
|
||||
return _store.Operations.SendAsync(deleteEmailOperation);
|
||||
}
|
||||
|
||||
private static string GetCompareExchangeKeyFromEmail(string email)
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
<PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.2.3" />
|
||||
<PackageReference Include="RavenDB.Client" Version="4.2.0" />
|
||||
<PackageReference Include="RavenDB.DependencyInjection" Version="3.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.2</TargetFramework>
|
||||
@@ -11,6 +11,7 @@
|
||||
<PackageReference Include="Microsoft.AspNetCore.App" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All" />
|
||||
<PackageReference Include="RavenDB.Client" Version="4.2.0" />
|
||||
<PackageReference Include="RavenDB.DependencyInjection" Version="3.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user