I\'m new to ASP.NET identity and am still trying to get my head around how it all works. Unfortunately I\'ve found many of the tutorials I\'ve tried are for Identity 1.0, wherea
In your examples, you seem to want to replace the DbContext
with something else but I believe that actually, you need to focus your efforts one level higher.
The framework has a class UserManager
which has the responsibility for managing, but not storing, the users and their related information. When it wants to store the users (or their related information) the default is to use the provided UserStore<IdentityUser>
which knows how to store IdentityUser
instances in a database using a DbContext
.
In the 2.0 framework, the various bits of the identity storing were broken into several interfaces. The default implementation provided, UserStore<IdentityUser>
implements several of these interfaces and stores the data for them all in the database using a DBContext
.
If you look at the defnition of the default provided entity framework based UserStore you can see that it implements many of these small interfaces:
public class UserStore<TUser, TRole, TKey, TUserLogin, TUserRole, TUserClaim> : IUserLoginStore<TUser, TKey>,
IUserClaimStore<TUser, TKey>, IUserRoleStore<TUser, TKey>, IUserPasswordStore<TUser, TKey>,
IUserSecurityStampStore<TUser, TKey>, IQueryableUserStore<TUser, TKey>, IUserEmailStore<TUser, TKey>,
IUserPhoneNumberStore<TUser, TKey>, IUserTwoFactorStore<TUser, TKey>, IUserLockoutStore<TUser, TKey>,
IUserStore<TUser, TKey>, IDisposable
where TUser : IdentityUser<TKey, TUserLogin, TUserRole, TUserClaim>
where TRole : IdentityRole<TKey, TUserRole>
where TKey : Object, IEquatable<TKey>
where TUserLogin : new(), IdentityUserLogin<TKey>
where TUserRole : new(), IdentityUserRole<TKey>
where TUserClaim : new(), IdentityUserClaim<TKey>
As you don't want to use Entity Framework at all, you need to provide your own implementations of some of these key interfaces which will store that data in the places you want the data to be stored. The main interface is IUserStore<Tuser,TKey>. this defines the contract for storing users which have a key of a particular type. If you only want to store users and no other information then you can implement this interface and then pass your implementation to the UserManager
and you should be good to go.
It's unlikely that this will be enough though as likely you will want passwords, roles, logins etc for your users. If so then you need to make your class which implements IUserStore<Tuser,TKey>
also implement IUserPasswordStore<TUser, TKey>
, IRoleStore<TRole, TKey>
and IUserClaimStore<TUser, TKey>
.
You can find a list of all the interfaces on MSDN here
Depending on the bits you want to use you need to implement those interfaces.
You will probably also need to define your own versions of the Identity*
classes which exist for the Entity framework already out of the box. So you will need your own IdentityUser
class which represents the users you want to store, and IdentityUserClaim
for the users claims. I haven't done this myself so I'm not exactly sure, but my feeling is that you will have to do this.
Scott Allen has a good article on the various bits of the model which might be useful.
As for your issues with this line:
AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, await user.GenerateUserIdentityAsync(UserManager));
There is a method called GenerateUserIdentityAsync
which is defined on Applicationuser
which extends IdentityUser
. It is defined in the template project I believe and looks something like this:
public class ApplicationUser : IdentityUser
{
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(
UserManager<ApplicationUser> manager) {
// Note the authenticationType must match the one
// defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity =
await manager.CreateIdentityAsync(this,
DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
}
As you are not using the entity framework IdentityUser
any more then you either need to define a similar method or your own User
class or implement the same functionality some other way (like just calling await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie)
instead)
I think this has been updated recently to this in ApplicationUser
:
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager, string authenticationType)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, authenticationType);
// Add custom user claims here
return userIdentity;
}
It is called like this from AccountController
-> GetExternalLogin
ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(UserManager,
OAuthDefaults.AuthenticationType);
ClaimsIdentity cookieIdentity = await user.GenerateUserIdentityAsync(UserManager,
CookieAuthenticationDefaults.AuthenticationType);
I am pretty new to Identity myself. Does your User entity implement the IUser interface? e.g.
public partial class User : IUser<Guid> //Whatever your key is
{
public Task<ClaimsIdentity> GenerateUserIdentityAsync(ApplicationUserManager manager)
{
return Task.FromResult(GenerateUserIdentity(manager));
}
public ClaimsIdentity GenerateUserIdentity(ApplicationUserManager manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = manager.CreateIdentity<User, Guid>(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
}
Then to sign in you can call the above:
public async Task SignInAsync(User user, bool isPersistent)
{
var userIdentity = await user.GenerateUserIdentityAsync(UserManager);
AuthenticationManager.SignIn(
new AuthenticationProperties
{
IsPersistent = isPersistent
},
userIdentity
);
}