Skip to content

Commit f5ee6b5

Browse files
committed
Add passkey help link
1 parent 362a8f6 commit f5ee6b5

File tree

2 files changed

+30
-2
lines changed

2 files changed

+30
-2
lines changed

src/Identity/EntityFrameworkCore/src/UserOnlyStore.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -758,7 +758,8 @@ private void ThrowIfPasskeysNotSupported()
758758
throw new InvalidOperationException(
759759
$"This operation is not permitted because the underlying '{nameof(DbContext)}' does not include '{typeof(TUserPasskey).Name}' in its model. " +
760760
$"When using '{nameof(IdentityDbContext)}', make sure that '{nameof(IdentityOptions)}.{nameof(IdentityOptions.Stores)}.{nameof(StoreOptions.SchemaVersion)}' " +
761-
$"is set to '{nameof(IdentitySchemaVersions)}.{nameof(IdentitySchemaVersions.Version3)}' or higher.");
761+
$"is set to '{nameof(IdentitySchemaVersions)}.{nameof(IdentitySchemaVersions.Version3)}' or higher. " +
762+
$"See https://aka.ms/aspnet/passkeys for more information.");
762763
}
763764
}
764765
}

src/Identity/EntityFrameworkCore/src/UserStore.cs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,8 @@ public class UserStore<TUser, TRole, TContext, [DynamicallyAccessedMembers(Dynam
138138
where TRoleClaim : IdentityRoleClaim<TKey>, new()
139139
where TUserPasskey : IdentityUserPasskey<TKey>, new()
140140
{
141+
private bool? _dbContextSupportsPasskeys;
142+
141143
/// <summary>
142144
/// Creates a new instance of the store.
143145
/// </summary>
@@ -160,7 +162,14 @@ public class UserStore<TUser, TRole, TContext, [DynamicallyAccessedMembers(Dynam
160162
private DbSet<TUserRole> UserRoles { get { return Context.Set<TUserRole>(); } }
161163
private DbSet<TUserLogin> UserLogins { get { return Context.Set<TUserLogin>(); } }
162164
private DbSet<TUserToken> UserTokens { get { return Context.Set<TUserToken>(); } }
163-
private DbSet<TUserPasskey> UserPasskeys { get { return Context.Set<TUserPasskey>(); } }
165+
private DbSet<TUserPasskey> UserPasskeys
166+
{
167+
get
168+
{
169+
ThrowIfPasskeysNotSupported();
170+
return Context.Set<TUserPasskey>();
171+
}
172+
}
164173

165174
/// <summary>
166175
/// Gets or sets a flag indicating if changes should be persisted after CreateAsync, UpdateAsync and DeleteAsync are called.
@@ -879,4 +888,22 @@ public virtual async Task RemovePasskeyAsync(TUser user, byte[] credentialId, Ca
879888
await SaveChanges(cancellationToken).ConfigureAwait(false);
880889
}
881890
}
891+
892+
private void ThrowIfPasskeysNotSupported()
893+
{
894+
if (_dbContextSupportsPasskeys == true)
895+
{
896+
return;
897+
}
898+
899+
_dbContextSupportsPasskeys ??= Context.Model.FindEntityType(typeof(TUserPasskey)) is not null;
900+
if (_dbContextSupportsPasskeys == false)
901+
{
902+
throw new InvalidOperationException(
903+
$"This operation is not permitted because the underlying '{nameof(DbContext)}' does not include '{typeof(TUserPasskey).Name}' in its model. " +
904+
$"When using '{nameof(IdentityDbContext)}', make sure that '{nameof(IdentityOptions)}.{nameof(IdentityOptions.Stores)}.{nameof(StoreOptions.SchemaVersion)}' " +
905+
$"is set to '{nameof(IdentitySchemaVersions)}.{nameof(IdentitySchemaVersions.Version3)}' or higher. " +
906+
$"See https://aka.ms/aspnet/passkeys for more information.");
907+
}
908+
}
882909
}

0 commit comments

Comments
 (0)