0

I have wired up my application to use ASP.NET Identity in an ASP.NET MVC environment, and it works great. I love it. But I have an issue with the field it uses;

Specifically, the login method.

    //
    // POST: /Account/Login
    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    [Route("account/login")]
    public async Task<ActionResult> Login(LoginViewModel model, string returnUrl) {
        if (ModelState.IsValid) {
            var user = await UserService.FindAsync(model.UserName, model.Password);
            if (user != null) {
                await SignInAsync(user, model.RememberMe);
                return RedirectToLocal(returnUrl);
            }
            else {
                ModelState.AddModelError("", "Invalid username or password.");
            }
        }

        // If we got this far, something failed, redisplay form
        return View(model);
    }

    private async Task SignInAsync(Member user, bool isPersistent) {
        AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);

        var identity = await UserService.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);

        AuthenticationManager.SignIn(
            new AuthenticationProperties() {
                IsPersistent = isPersistent
            },
            identity);
    }

This creates an authentication ticket using the UserName field of the Member class that is coded against the IUser system. Now, that does work, but I want it to use the Email field.

The reason is because I use User.Identity.Name for some things, and I really want it to equal the value in the Email field.

Unfortunately, there is no Email field on IUser. I'm having a hard time figuring out how to do this. Right now, I am doing it by setting UserName to always get or set the Email field, like this.

public class Member : IUser {
   // ...
   public string Email { get; set; }
   public string UserName { get { return Email; } set { Email = value; } }
   // ...
}

but that's a very 'hacky' way to do it, I'd like to learn a cleaner method.

Ciel
  • 4,290
  • 8
  • 51
  • 110
  • Is the username supposed to be the email? If so, then it isn't hacky. – jamesSampica Mar 22 '15 at 04:05
  • No, the username is not supposed to be the email, but email address is what I would prefer it to lookup and store by. – Ciel Mar 22 '15 at 04:06
  • 1
    See if [my answer here helps](http://stackoverflow.com/questions/27683169/identity-2-0-creating-custom-claimsidentity-eg-user-identity-getuserbyidint/27694574#27694574) you. It extends the identity object to return a property from your claims token. – jamesSampica Mar 22 '15 at 04:09
  • That's a very interesting article, and I think it does explain a few things - but the biggest problem is that username isn't a unique field in my application. Email address is the only unique field, as it is the primary key, so to speak. – Ciel Mar 22 '15 at 04:14
  • if email is the unique name for your user then it should be the username. What you have is okay. – jamesSampica Mar 22 '15 at 04:38

1 Answers1

1

I think you need to extend IIdentity and IPrincipal. I have written a post here.

//We will create a user identity class.This class will implement IIdentity interface.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Security.Principal;


namespace TechBook.Presentation.LoginClasses
{
    public class UserIdentity: IIdentity
    {
        private bool isAuthenticated;
        private string authenticationType;
        private string userID;
        private string firstName;
        private string lastName;
        private List roles;

        public UserIdentity(string UserID, bool IsAuthenticated, string AuthenticationType)
        {
            userID = UserID;
            isAuthenticated = IsAuthenticated;
            authenticationType = AuthenticationType;
        }


        public bool IsAuthenticated
        {
            get { return isAuthenticated; }
        }
        public string AuthenticationType
        {
            get { return authenticationType; }
        }


        public string Name
        {
            get { return userID; }
        }


        public string FirstName
        {
            get { return firstName; }
            set { firstName = value; }
        }


        public string LastName
        {
            get { return lastName; }
            set { lastName = value; }
        }


        public List Roles
        {
            get { return roles; }
            set { roles = value; }
        }
    }
}


//We will create a custom principal class. The class will implement IPrincipal interface.   


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Security.Principal;


namespace TechBook.Presentation.LoginClasses
{
    public class UserPrincipal :IPrincipal
    {
        private UserIdentity _userIdentity;


        public UserPrincipal(UserIdentity userIdentity)
        {
            _userIdentity = userIdentity;
        }


        public System.Security.Principal.IIdentity Identity
        {
            get { return _userIdentity; }
        }


        public bool IsInRole(string role)
        {
            return _userIdentity.Roles.Contains(role);
        }
    }
}

/*We have created these classes as we know identity and role are must to implement authentication and authorization.  Application must be able to identify the user.

Now we need to write code for user authentication. */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace TechBook.Presentation.LoginClasses
{
    public class SecurityManager
    {
        public bool Authenticate(string userName, string password)
        {
            BusinessEngine.Users user = new BusinessEngine.Users();

            user.UserName = userName;
            user.Password = password;

            if (new Business.Controller.UserController().validateUser(user) == 1)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        public UserPrincipal ConstructUserPrincipal(System.Security.Principal.IIdentity iidentity)
        {
            int userId = Convert.ToInt32(iidentity.Name);

            if (userId &gt; 0)
            {
                BusinessEngine.Users user = new BusinessEngine.Users();
                user = new Business.Controller.UserController().getUserById(userId);

                UserIdentity uidentity = new UserIdentity(userId.ToString(), iidentity.IsAuthenticated, iidentity.AuthenticationType);
                uidentity.FirstName = user.FirstName;
                uidentity.LastName = user.LastName;

                List role = new List();
                if (user.UserType.ToString().ToUpper().Equals("A"))
                {
                    role.Add("Admin");
                    uidentity.Roles = role;
                }

                UserPrincipal uprincipal = new UserPrincipal(uidentity);

                return uprincipal;
            }
            else
            {
                return null;
            }
        }
    }
}

/*We have kept the userId in Context.User.Identity.Name (see UserIdentity class). using this we can query the database and get the user information. 

Login Code*/


protected void btnLogin_Click(object sender, EventArgs e)
        {
            TechBook.Presentation.LoginClasses.SecurityManager obj = new                    TechBook.Presentation.LoginClasses.SecurityManager();
            if (obj.Authenticate(txtUserName.Text.Trim(), txtPassword.Text.Trim()))
            {
                BusinessEngine.Users user = new BusinessEngine.Users();
                user.UserName = txtUserName.Text.Trim();
                user.Password = txtPassword.Text.Trim();

                user = new Business.Controller.UserController().getUser(user);
                FormsAuthentication.RedirectFromLoginPage(user.UserId.ToString(), false);
            }
        }

/*We need user and role information everytime a request is received and thus we need to bind the code with authentication module. 

Global.asax code*/


protected void Application_AuthenticateRequest(object sender, EventArgs e)
        {
            if (this.User != null)
            {
                TechBook.Presentation.LoginClasses.SecurityManager obj = new TechBook.Presentation.LoginClasses.SecurityManager();

                TechBook.Presentation.LoginClasses.UserPrincipal principal = obj.ConstructUserPrincipal(this.User.Identity);

                this.Context.User = principal;

            }
        }
Anuj Yadav
  • 980
  • 11
  • 20