Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Where can I load the user information to the session in ASP.NET MVC 5 with windows authentication?

Tags:

I want to use the ASP.NET MVC 5 for my web app. I need use the windows authentication.

If I use the windows authentication where is the best place for reading user information (userid and roles) and store its to the Session?

I have the method for getting the user information by username from the database like this:

public class CurrentUser
    {
        public int UserId { get; set; }

        public string UserName { get; set; }

        public Roles Roles { get; set; }
    }

    public enum Roles
    {
        Administrator,
        Editor,
        Reader
    }

    public class AuthService
    {
        public CurrentUser GetUserInfo(string userName)
        {
            var currentUser = new CurrentUser();

            //load from DB

            return currentUser;
        }
    }
like image 941
Jenan Avatar asked Sep 12 '16 11:09

Jenan


People also ask

How can we maintain user session in MVC 5?

ASP.NET MVC provides three ways (TempData, ViewData and ViewBag) to manage session, apart from that we can use session variable, hidden fields and HTML controls for the same.

How can store data in session in ASP.NET MVC?

To store data in session, we do as we used to do in ASP.NET Web Form. Session stores the data in key and value format. Value gets stored in object format, so any type of data (string, integer, class collection etc.) can be stored into the Session.


1 Answers

You've asked two questions (1) the best place to obtain user information and (2) how to store it in the Session. I'll answer (1) and in so doing perhaps show that you need not put any additional information in the session.

You've stated that your application is using Windows Authentication, so that means the hard work of authenticating the user has already been done by IIS/HttpListener before your app receives the request. When you receive the request there will be a WindowsPrincipal in HttpContext.User. This will have the windows username and AD roles already established, but you wish to use additional roles stored in the database...

You could access your AuthService from anywhere in your application, but probably the best approach is to register an IAuthorizationFilter and do the work there. By following this approach, the additional roles and other information you fetch from the database will be available in your controller methods and, perhaps more importantly, from any additional library code that needs to check user credentials.

Prior to .Net 4.5, if you wanted to add additional information to the WindowsPrincipal I think your only choice was to replace the system-provided User with another object that implemented the IPrincipal interface. This approach is still available (and what I recommend), but since the introduction of Windows Identity Foundation (WIF) in .Net 4.5, WindowsPrincipal is derived from  System.Security.Claims.ClaimsIdentityClaimsIdentity, which supports adding additional roles (and other useful information) to the system-provided principal. However, as several people have found, there is a bug/feature in Windows which can cause an exception The trust relationship between the primary domain and the trusted domain failed to be thrown when checking roles that have been added programmatically. We have found that a simple and reliable way to avoid this is to replace the User with a GenericPrincipal.

Steps required:

(1) create an IAuthorizationFilter.

class MyAuthorizationFilter : IAuthorizationFilter
{
    AuthService _authService;

    public MyAuthorizationFilter(AuthService authService)
    {
        _authService = authService;
    }

    public void OnAuthorization(AuthorizationContext filterContext)
    {
        var principal = filterContext.HttpContext.User;

        if (principal.Identity != null && principal.Identity.IsAuthenticated)
        {
            // Add username (and other details) to session if you have a need
            filterContext.HttpContext.Session["User"] = principal.Identity.Name;

            // get user info from DB and embue the identity with additional attributes
            var user = _authService.GetUserInfo(principal.Identity.Name);

            // Create a new Principal and add the roles belonging to the user
            GenericPrincipal gp = new GenericPrincipal(principal.Identity, user.RoleNames.ToArray());
            filterContext.HttpContext.User = gp;
        }
    }
}

(2) Register your filter. This can be registered at the controller level or globally. Typically you will do this in App_Start\FilterConfig.cs:

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new MyAuthorizationFilter(new AuthService()));
    }
}

(3) Use the provided GenericPrincipal in your application code to answer questions about the user identification and other credentials. e.g. in your controller method you can access the username or any other "claims" (e.g. email address) stored in the GenericPrincipal by your filter.

        public ActionResult Index()
        {
            ViewBag.Name = HttpContext.User.Identity.Name;
            if(HttpContext.User.IsInRole("Administrator"))
            {
                // some role-specific action
            } 
            return View();
        }

Because you've used the built-in mechanism to record Principal roles, you can access user details from anywhere using HttpContext.User or System.Threading.Thread.CurrentPrincipal. Also you can use the AuthorizeAttribute in you controller methods to declare which actions are available to certain roles or users. e.g.

   public class HomeController : Controller
    {
        [Authorize(Roles = "Administrator")]
        public ActionResult Admin()
        {
            return View();
        }

See MSDN for further details about ClaimsIdentity

I hope this helps

-Rob

like image 164
Rob Avatar answered Sep 26 '22 16:09

Rob