6

What I Need?! I have an ASP.NET identity system setup and running with external logins. For whatever reason i need to setup a custom authentication after the ASP.NET identity authentication. Let me explain how? Lets say I have three pages for the users to view on my application, Page A,B,C. Who can view Page A? Any anonymous user can view page A. Who can view Page A & B? Any user who have created an account either with his/her email & password or with external logins. Who can view Page A,B & C?

Here is the place i want to set custom authentication. Any user who have created an account either with his/her email account or external logins AND has a valid serial key. Serial Key? I set a class in ASP.NET identity as below:

 public class UserDetails : IdentityUser
    {
        public virtual MembershipSerial MembershipSerial { get; set; }
    }

    public class MembershipSerial
    {
        [HiddenInput(DisplayValue=false)]
        public int Id { get; set; }
        [HiddenInput(DisplayValue=false)]
        public string Serial { get; set; }
        [Required]
        [Display(Name="Membership Serial")]
        public string SerialConfirmed { get; set; }
    }

    public class MyDbContext : IdentityDbContext<UserDetails>
    {
        public MyDbContext()
            : base ("EFDbContext")
        {
        }
        public System.Data.Entity.DbSet<MembershipSerial> MembershipSerial { get; set; }
    }

As you see above class i set up three properties in the class. Field Id is for the Ids of the serials, The Serial is a 14 Alpha numeric letters which is entered by the administrator and as you can see it is a hidden field which not allowing null. The field SerialConfirmed is also a 14 Alpha Numeric letters which will be entered by the users to authenticate in order to do some certain tasks in the application. The whole concept is, that a logged in user should be pushed for a second type authentication which is authentication vs serial numbers.

I am seriously in need of help and searching online didn't help too much. If you need more information or yet its is unclear don't hesitate to ask me. Regards Edit: I am using EF code first. Dostdar

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
Coding Freak
  • 418
  • 1
  • 8
  • 27
  • So, the scenario is that a user logs in, attempts to access a page of some sort (or execute some action), and is then presented with some sort of challenge UI? If they enter a valid code, they are allowed to access that page, and only that page (or action)? – Tieson T. Apr 24 '16 at 07:16
  • @TiesonT. Exactly that is what i want – Coding Freak Apr 24 '16 at 07:18
  • 1
    In some cases the one authenticating with the serials is allowed to do multiple action – Coding Freak Apr 24 '16 at 07:19
  • 1
    Is the behavior always the same on the same action? Meaning, everyone accesses the action the same way, but has their own unique "authorization code" to enter? – Tieson T. Apr 24 '16 at 07:19
  • 1
    yes the behavior is the same for every logged in user with a unique key. Mean that every logged in user should have their own key. – Coding Freak Apr 24 '16 at 07:21

1 Answers1

0

It seems like a custom authorization attribute would work. Here's an example implementation:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
public class RequiresSerialValidationAttribute : AuthorizeAttribute
{
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        bool hasValidSerial = false;
        if (filterContext.HttpContext.Request.IsAuthenticated)
        {
            string userName = filterContext.HttpContext.User.Identity.Name;

            if (!string.IsNullOrWhiteSpace(userName))
            {       
                string serial = string.Empty;// TODO: Retrieve user's previously authenticated serial, perhaps from Session or a cookie?

                if(!string.IsNullOrWhiteSpace(serial))
                {
                    var service = DependencyResolver.Current.GetService<IYourAuthService>();
                    hasValidSerial = service.IsSerialValidForUser(userName, serial);
                }
            }
        }

        if (!hasValidSerial)
        {
            filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new { controller = "yourserialauthcontroller", action = "yourauthaction", area = string.Empty }));
        }
        else
        {
            base.OnAuthorization(filterContext);
        }
    }
}

You would decorate the action methods with this attribute:

[RequireSerialValidation]
public ActionResult SomeAction()
{
}

The attribute would trigger a redirect to your challenge action, where you prompt your user for their serial. Assuming all goes well, you store their serial somewhere (Session could work here, or create an encrypted cookie), and then redirect back to the original action. On this second attempt, you've already verified that the action is allowed, so no redirect occurs.

Your authentication service can be whatever you want it to be. In this example, I assume you're using dependency injection and that you've configured the global dependency resolver. Given that, your IYourAuthService could look like this (omitting other methods):

public IYourAuthService
{
    bool IsSerialValidForUser(string userName, string serial);
}

with an implementation like so:

public YourAuthService : IYourAuthService
{
    public bool IsSerialValidForUser(string userName, string serial)
    {
        using(var context = new YourEntityFrameworkDbContext())
        {
            return context.Users.Any(u => u.UserName.Equals(userName, StringComparison.OrdinalIgnoreCase) && u.Serial.Equals(serial, StringComparison.OrdinalIgnoreCase));
        }
    }
}

This assumes you have a table called User (or Users) in your database, and that UserName and Serial are fields on that table. StringComparison.OrdinalIgnoreCase lets you do a case-insensitive, culture-insensitive match on the strings you're attempting to compare.

Tieson T.
  • 20,774
  • 6
  • 77
  • 92
  • How can i compare the serial entered by the user with the serial i already have in my sql table? – Coding Freak Apr 24 '16 at 08:24
  • That would happen in your version of the service class I allude to in the line that starts with "var service =...". – Tieson T. Apr 24 '16 at 08:27
  • Tieson I am really sorry to ask you this, as you know i am really a beginner would you please update your question for fetching the data from database and comparing both? I tried hard but couldn't catch anything from the code above as far as its on expert level. Thanks a lot for your effort. I really need your help – Coding Freak Apr 24 '16 at 09:26