Can we use ASP.NET Identity in Domain Driven Design? Can we use ASP.NET Identity in Domain Driven Design? asp.net asp.net

Can we use ASP.NET Identity in Domain Driven Design?


The questions reveals several misconceptions:

It appears that you perceive the domain model as some monolithic model where you put every piece of application in. Instead, concentrate on strategic patterns to distinguish Bounded Contexts. Consider the domain as a composition of several loosely interconnected components. Then identify what your core domain is and apply DDD tactical patterns there. Not every ccomponent needs DDD. Some of them even should not use DDD. Especially - generic domains, like Authentication.

DDD is technology agnostic (to some point) so yes, you can use ASP.NET Identity or whatever library you like.

Authentication typically belongs to the Application layer, not Domain layer.

However - if in your domain there is a concept of a user/client/person, it might be required to use the identity provided by the identity component. But you have to understand that the meaning of User in your bounded context is different than meaning of User in Identity component. These are not the same concept. Although they both refer to the same physical person sitting somewhere and clicking on your app's GUI, they are 2 different models (or projections) of him that serve different purposes. So you shouldn't just reuse the ASP.NET User class in your bounded context.

Instead - separate contexts should communicate via an anticorruption layer. Basically you have to make some service (interface only) in your bounded context that produces context-specific User objects. The implementation of that interface made in infrastructure layer will be a wrapper of ASP.NET Identity that gets ASP.NET Identity user and produce corresponding bounded context's user.


I am new to DDD. But I achieved integration with Identity and DDD. Although I doubt it truly sticks to the priciples of DDD.

I started with the Entity:

public partial class User : IdentityUser {        public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<User> manager) {            var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);            // Add custom user claims here            return userIdentity;        }        /// <summary>        /// The Date the User Registered for general information purposes        /// </summary>        public DateTime DateRegistered { get; set; }    }

Then the Interface:

public interface IUserRepository:IBaseRepository<User> {        /// <summary>        /// Register User to Identity Database        /// </summary>        /// <param name="userManager">User Manager to Handle Registration</param>        /// <param name="user">User to add to database</param>        /// <param name="password">User's password</param>        /// <returns>Identity Result</returns>        Task<IdentityResult> Register(UserManager<User, string> userManager, User user, string password);        /// <summary>        /// Login User        /// </summary>        /// <param name="signinManager">Signin Manager to handle login</param>        /// <param name="email">Email of user</param>        /// <param name="password">Password of user</param>        /// <param name="rememberMe">Boolean if the user wants to be remembered</param>        /// <returns>SignIn Status</returns>        Task<SignInStatus> Login(SignInManager<User, string> signinManager, string email, string password, bool rememberMe);        /// <summary>        /// Verify that code sent to User is valid        /// </summary>        /// <param name="signinManager">Signin Manager to handle verification</param>        /// <param name="provider">Provider of the code</param>        /// <param name="code">The code</param>        /// <param name="rememberMe">Boolean if user wants to be remembered</param>        /// <param name="rememberBrowser">Boolean if browser should be remembered</param>        /// <returns>SignIn Status</returns>        Task<SignInStatus> VerifyCode(SignInManager<User, string> signinManager, string provider, string code, bool rememberMe, bool rememberBrowser);        /// <summary>        /// Confirm email of User        /// </summary>        /// <param name="userManager">User Manager to handle confirmation</param>        /// <param name="userId">String user Id of the User</param>        /// <param name="code">User code sent in Email</param>        /// <returns>Identity Result</returns>        Task<IdentityResult> ConfirmEmail(UserManager<User, string> userManager, string userId, string code);        void ForgotPassword();        void ForgotPasswordConfirmation();        void ResetPassword();        void ResetPasswordConfirmation();        void ExternalLogin();        void SendCode();        void ExternalLoginCallback();        void ExternalLoginConfirmation();        /// <summary>        /// Log off user from the Application        /// </summary>        /// <param name="AuthenticationManager">Application Manager to handle Sign out</param>        void Logoff(IAuthenticationManager AuthenticationManager);        /// <summary>        /// Get user based on their Email        /// </summary>        /// <param name="Email">Email of user</param>        /// <returns>User</returns>        User GetUser(string Email);        /// <summary>        /// Get User by their GUID        /// </summary>        /// <param name="ID">GUID</param>        /// <returns>User</returns>        User GetUserById(string ID);    }

Then the Repository:

public class UserRepository : BaseRepository<User>, IUserRepository {        /// <summary>        /// Confirm email of User        /// </summary>        /// <param name="userManager">User Manager to handle confirmation</param>        /// <param name="userId">String user Id of the User</param>        /// <param name="code">User code sent in Email</param>        /// <returns>Identity Result</returns>        public async Task<IdentityResult> ConfirmEmail(UserManager<User, string> userManager, string userId, string code) =>            await userManager.ConfirmEmailAsync(userId, code);        public void ExternalLogin() {            throw new NotImplementedException();        }        public void ExternalLoginCallback() {            throw new NotImplementedException();        }        public void ExternalLoginConfirmation() {            throw new NotImplementedException();        }        public void ForgotPassword() {            throw new NotImplementedException();        }        public void ForgotPasswordConfirmation() {            throw new NotImplementedException();        }        /// <summary>        /// Get user based on their Email        /// </summary>        /// <param name="Email">Email of user</param>        /// <returns>User</returns>        public User GetUser(string Email) =>            _context.Users.Where(p => p.Email == Email).FirstOrDefault();        /// <summary>        /// Get User by their GUID        /// </summary>        /// <param name="ID">GUID</param>        /// <returns>User</returns>        public User GetUserById(string ID) =>             _context.Users.Find(ID);        /// <summary>        /// Login User        /// </summary>        /// <param name="signinManager">Signin Manager to handle login</param>        /// <param name="email">Email of user</param>        /// <param name="password">Password of user</param>        /// <param name="rememberMe">Boolean if the user wants to be remembered</param>        /// <returns>SignIn Status</returns>        public async Task<SignInStatus> Login(SignInManager<User, string> signinManager, string email, string password, bool rememberMe) =>            await signinManager.PasswordSignInAsync(email, password, rememberMe, shouldLockout: false);        /// <summary>        /// Log off user from the Application        /// </summary>        /// <param name="AuthenticationManager">Application Manager to handle Sign out</param>        public void Logoff(IAuthenticationManager AuthenticationManager) {            AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);        }        /// <summary>        /// Register User to Identity Database        /// </summary>        /// <param name="userManager">User Manager to Handle Registration</param>        /// <param name="user">User to add to database</param>        /// <param name="password">User's password</param>        /// <returns>Identity Result</returns>        public async Task<IdentityResult> Register(UserManager<User, string> userManager, User user, string password) =>            await userManager.CreateAsync(user, password);        public void ResetPassword() {            throw new NotImplementedException();        }        public void ResetPasswordConfirmation() {            throw new NotImplementedException();        }        public void SendCode() {            throw new NotImplementedException();        }        /// <summary>        /// Verify that code sent to User is valid        /// </summary>        /// <param name="signinManager">Signin Manager to handle verification</param>        /// <param name="provider">Provider of the code</param>        /// <param name="code">The code</param>        /// <param name="rememberMe">Boolean if user wants to be remembered</param>        /// <param name="rememberBrowser">Boolean if browser should be remembered</param>        /// <returns>SignIn Status</returns>        public async Task<SignInStatus> VerifyCode(SignInManager<User, string> signinManager, string provider, string code, bool rememberMe, bool rememberBrowser) =>            await signinManager.TwoFactorSignInAsync(provider, code, isPersistent: rememberMe, rememberBrowser: rememberBrowser);    }

IService:

public interface IUserService {        /// <summary>        /// Register User to Identity Database        /// </summary>        /// <param name="userManager">User Manager to Handle Registration</param>        /// <param name="user">User to add to database</param>        /// <param name="password">User's password</param>        /// <returns></returns>        Task<IdentityResult> Register(UserManager<User, string> userManager, User user, string password);        /// <summary>        /// Login User        /// </summary>        /// <param name="signinManager">Signin Manager to handle login</param>        /// <param name="email">Email of user</param>        /// <param name="password">Password of user</param>        /// <param name="rememberMe">Boolean if the user wants to be remembered</param>        /// <returns></returns>        Task<SignInStatus> Login(SignInManager<User, string> signinManager, string email, string password, bool rememberMe);        /// <summary>        /// Verify that code sent to User is valid        /// </summary>        /// <param name="signinManager">Signin Manager to handle verification</param>        /// <param name="provider">Provider of the code</param>        /// <param name="code">The code</param>        /// <param name="rememberMe">Boolean if user wants to be remembered</param>        /// <param name="rememberBrowser">Boolean if browser should be remembered</param>        /// <returns></returns>        Task<SignInStatus> VerifyCode(SignInManager<User, string> signinManager, string provider, string code, bool rememberMe, bool rememberBrowser);        /// <summary>        /// Confirm email of User        /// </summary>        /// <param name="userManager">User Manager to handle confirmation</param>        /// <param name="userId">String user Id of the User</param>        /// <param name="code">User code sent in Email</param>        /// <returns></returns>        Task<IdentityResult> ConfirmEmail(UserManager<User, string> userManager, string userId, string code);        void ForgotPassword();        void ForgotPasswordConfirmation();        void ResetPassword();        void ResetPasswordConfirmation();        void ExternalLogin();        void SendCode();        void ExternalLoginCallback();        void ExternalLoginConfirmation();        /// <summary>        /// Log off user from the Application        /// </summary>        /// <param name="AuthenticationManager">Application Manager to handle Sign out</param>        void Logoff(IAuthenticationManager AuthenticationManager);        /// <summary>        /// Get user based on their Email        /// </summary>        /// <param name="Email">Email of user</param>        /// <returns>User</returns>        User GetUser(string Email);        /// <summary>        /// Get User by their GUID        /// </summary>        /// <param name="ID">GUID</param>        /// <returns>User</returns>        User GetUserById(string ID);    }

Service:

public class UserService : ServiceBase, IUserService {        #region Private Field        private IUserRepository _userRepository;        #endregion        #region Constructor        /// <summary>        /// Constructor to initialise User Repository        /// </summary>        /// <param name="userRepository"></param>        public UserService(IUserRepository userRepository) {            _userRepository = userRepository;        }        #endregion        #region Methods        /// <summary>        /// Confirm email of User        /// </summary>        /// <param name="userManager">User Manager to handle confirmation</param>        /// <param name="userId">String user Id of the User</param>        /// <param name="code">User code sent in Email</param>        /// <returns>Identity Result</returns>        public Task<IdentityResult> ConfirmEmail(UserManager<User, string> userManager, string userId, string code) =>            _userRepository.ConfirmEmail(userManager, userId, code);        public void ExternalLogin() {            throw new NotImplementedException();        }        public void ExternalLoginCallback() {            throw new NotImplementedException();        }        public void ExternalLoginConfirmation() {            throw new NotImplementedException();        }        public void ForgotPassword() {            throw new NotImplementedException();        }        public void ForgotPasswordConfirmation() {            throw new NotImplementedException();        }        /// <summary>        /// Get user based on their Email        /// </summary>        /// <param name="Email">Email of user</param>        /// <returns>User</returns>        public User GetUser(string Email) {            throw new NotImplementedException();        }        /// <summary>        /// Get User by their GUID        /// </summary>        /// <param name="ID">GUID</param>        /// <returns>User</returns>        public User GetUserById(string ID) {            throw new NotImplementedException();        }        /// <summary>        /// Login User        /// </summary>        /// <param name="signinManager">Signin Manager to handle login</param>        /// <param name="email">Email of user</param>        /// <param name="password">Password of user</param>        /// <param name="rememberMe">Boolean if the user wants to be remembered</param>        /// <returns>SignIn Status</returns>        public Task<SignInStatus> Login(SignInManager<User, string> signinManager, string email, string password, bool rememberMe) =>            _userRepository.Login(signinManager, email, password, rememberMe);        /// <summary>        /// Log off user from the Application        /// </summary>        /// <param name="AuthenticationManager">Application Manager to handle Sign out</param>        public void Logoff(IAuthenticationManager AuthenticationManager) {            _userRepository.Logoff(AuthenticationManager);        }        /// <summary>        /// Register User to Identity Database        /// </summary>        /// <param name="userManager">User Manager to Handle Registration</param>        /// <param name="user">User to add to database</param>        /// <param name="password">User's password</param>        public Task<IdentityResult> Register(UserManager<User, string> userManager, User user, string password) =>            _userRepository.Register(userManager, user, password);        public void ResetPassword() {            throw new NotImplementedException();        }        public void ResetPasswordConfirmation() {            throw new NotImplementedException();        }        public void SendCode() {            throw new NotImplementedException();        }        /// <summary>        /// Verify that code sent to User is valid        /// </summary>        /// <param name="signinManager">Signin Manager to handle verification</param>        /// <param name="provider">Provider of the code</param>        /// <param name="code">The code</param>        /// <param name="rememberMe">Boolean if user wants to be remembered</param>        /// <param name="rememberBrowser">Boolean if browser should be remembered</param>        /// <returns>SignIn Status</returns>        public Task<SignInStatus> VerifyCode(SignInManager<User, string> signinManager, string provider, string code, bool rememberMe, bool rememberBrowser) =>            _userRepository.VerifyCode(signinManager, provider, code, rememberMe, rememberBrowser);        #endregion    }


You can use anything you like. But be aware of pollution particular solution is going to make. If your domain model gets messed up with hundreds of lines of asp.net technical kind of plumbing code that makes your domain logic hard to perceive and you are missing point of DDD.

In ideal situation - your domain model should depend only on programming language.

Also - you might find something useful from my long time ago implementation of user session related code.