Search code examples
c#asp.net-mvcmodel-view-controllerwindows-authentication

Authenticate from Active Directory but Authorize Roles from SQL Database in MVC


I am new to MVC. I searched and found no solution that fits for my requirements.

I am developing a web portal for our team's internal use which uses Windows AD authentication for login. However, for role based access I have created a local database which can return the Role details for the user. I have created a custom Authorization filter that allows me to handle authorization based on the user's role. This filter is querying details from the DB however the issue with this approach is, it will try to get details from DB for every request to the controller which makes it expensive.

How can I save the user details fetched from the DB in a Token such that I don't have to query DB for every request and use the Token values inside the Authorization filter. Also, I can use the values retrieved for the user from the database, anywhere else in the app. (There are some other details for the user we have in the Database).

If someone can suggest a better way to achieve this, please help.

Here is the code that I am currently using inside Authorization filter:

public class AuthorizeRole : AuthorizeAttribute
{
    private bool _authenticated;
    private bool _authorized;

    public string InRoles { get; set; }

    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        base.HandleUnauthorizedRequest(filterContext);

        if (_authenticated && !_authorized)
        {
            filterContext.Result = new RedirectResult("/account/error");
        }
    }

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        _authenticated = base.AuthorizeCore(httpContext);

        if (_authenticated)
        {
            if (string.IsNullOrEmpty(InRoles))
            {
                _authorized = true;
                return _authorized;
            }

            if (!string.IsNullOrEmpty(httpContext.User.Identity.Name))
            {
                string NTID = httpContext.User.Identity.Name.Split('\\')[1];
                var roles = InRoles.Split(',');

                using (Models.UserAuthEntities userAuthEntities = new Models.UserAuthEntities())
                {
                    try
                    {
                        ObjectResult<Models.Validate_User_Login_Result> userResults = userAuthEntities.Validate_User_Login(NTID);
                        var user = userResults.FirstOrDefault(all => all.NTID == NTID);

                        if (user == null)
                        {
                            _authorized = false;
                            return _authorized;
                        }
                        else
                        {
                            if (roles.Contains(user.Role))
                            {
                                return _authorized;
                            }
                        }
                    }
                    catch (Exception)
                    {
                        _authorized = false;
                        return _authorized;
                    }
                }
            }
            else
            {
                _authorized = false;
                return _authorized;
            }
        }

        _authorized = false;
        return _authorized;
    }
}

Please suggest at which section to use the code you will be suggesting (like, inside controller, inside filter or somewhere else.)

I found this solution at: this site but there it is used for AD groups.


Solution

  • I have checked the cookie in override version of method AuthorizeCore it is working now:

        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            string cookieName = FormsAuthentication.FormsCookieName;
            HttpCookie authCookie = httpContext.Request.Cookies[cookieName];
            _authenticated = base.AuthorizeCore(httpContext);
            string authToken = httpContext.Request.Headers["Auth-Token"];
    
            if (_authenticated)
            {
                if (authCookie == null)
                {
                    if (string.IsNullOrEmpty(InRoles))
                    {
                        _authorized = true;
                        return _authorized;
                    }
    
                    if (!string.IsNullOrEmpty(httpContext.User.Identity.Name))
                    {
                        string NTID = httpContext.User.Identity.Name.Split('\\')[1];
                        var roles = InRoles.Split(',');
    
                        using (Models.UserAuthEntities userAuthEntities = new Models.UserAuthEntities())
                        {
                            try
                            {
                                ObjectResult<Models.Validate_User_Login_Result> userResults = userAuthEntities.Validate_User_Login(NTID);
                                var user = userResults.FirstOrDefault(all => all.NTID == NTID);
    
                                if (user == null)
                                {
                                    _authorized = false;
                                    return _authorized;
                                }
                                else
                                {
                                    if (roles.Contains(user.Role))
                                    {
                                        _authorized = true;
                                        return _authorized;
                                    }
                                }
                            }
                            catch (Exception)
                            {
                                _authorized = false;
                                return _authorized;
                            }
                        }
                    }
                    else
                    {
                        _authorized = false;
                        return _authorized;
                    }
                }
            }
    
            _authorized = false;
            return _authorized;
        }