我在哪里可以使用 windows 身份验证将用户信息加载到 ASP.NET MVC 5 中的会话?

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

我想为我的网络应用程序使用 ASP.NET MVC 5。我需要使用 windows authentication.

如果我使用 windows authentication 读取用户信息(用户 ID 和角色)并将其存储到 Session?

的最佳位置

我有这样的方法通过用户名从数据库中获取用户信息:

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;
        }
    }

首先也是最重要的:从不,从不从不在会话中存储用户详细信息.严重地。只是不要这样做。

如果您使用的是 Windows 身份验证,则用户位于 AD 中。您已使用 AD 获取用户信息。 Microsoft 有一个 MSDN article 描述应该如何完成。

总而言之,您创建了 UserIdentity 的子class,并使用您想要 return 用户的附加属性对其进行扩展:

[DirectoryRdnPrefix("CN")]
[DirectoryObjectClass("inetOrgPerson")]
public class InetOrgPerson : UserPrincipal
{
    // Inplement the constructor using the base class constructor. 
    public InetOrgPerson(PrincipalContext context) : base(context)
    {
    }

    // Implement the constructor with initialization parameters.    
    public InetOrgPerson(PrincipalContext context, 
                         string samAccountName, 
                         string password, 
                         bool enabled)
                         : base(context, 
                                samAccountName, 
                                password, 
                                enabled)
    {
    }

    InetOrgPersonSearchFilter searchFilter;

    new public InetOrgPersonSearchFilter AdvancedSearchFilter
    {
        get
        {
            if ( null == searchFilter )
                searchFilter = new InetOrgPersonSearchFilter(this);

            return searchFilter;
        }
    }

    // Create the mobile phone property.    
    [DirectoryProperty("mobile")]
    public string MobilePhone
    {
        get
        {
            if (ExtensionGet("mobile").Length != 1)
                return null;

            return (string)ExtensionGet("mobile")[0];
        }

        set
        {
            ExtensionSet( "mobile", value );
        }
    }

    ...
}

在上面的示例代码中,添加了一个 属性 以绑定到 AD 的用户的 mobile 字段。这是通过使用 ExtensionSet 实现 属性,然后使用 DirectoryProperty 属性注释 属性 来告诉它绑定到哪个字段来完成的。

class 上的 DirectoryRdnPrefixDirectoryObjectClass 属性需要与您的 AD 设置方式保持一致。

一旦实现,您就可以通过引用它们来简单地获取值 User.Identity。例如,User.Identity.MobilePhone 将为用户 return 来自 AD 的 mobile 字段。

您问了两个问题(1)获取用户信息的最佳位置和(2)如何将其存储在会话中。我会回答 (1),这样做可能表明您不需要在会话中添加任何其他信息。

您已经声明您的应用程序正在使用 Windows 身份验证,这意味着在您的应用程序收到请求之前,IIS/HttpListener 已经完成了对用户进行身份验证的艰苦工作。当您收到请求时,HttpContext.User 中会有一个 WindowsPrincipal。这将具有已经建立的 windows 用户名和 AD 角色,但您希望使用存储在数据库中的其他角色...

您可以从应用程序的任何位置访问您的 AuthService,但最好的方法可能是注册一个 IAuthorizationFilter 并在那里完成工作。通过采用这种方法,您从数据库中获取的其他角色和其他信息将在您的控制器方法中可用,也许更重要的是,从需要检查用户凭据的任何其他库代码中可用。

在 .Net 4.5 之前,如果您想向 WindowsPrincipal 添加额外的信息,我认为您唯一的选择是将系统提供的 User 替换为另一个实现了 IPrincipal 接口的对象.这种方法仍然可用(也是我推荐的),但是由于在.Net 4.5中引入了Windows身份基础(WIF),WindowsPrincipal派生自 System.Security.Claims.ClaimsIdentityClaimsIdentity,它支持添加额外的角色(和其他有用的信息)给系统提供的主体。但是,正如一些人发现的那样,Windows 中有一个 bug/feature,这会导致在检查以编程方式添加的角色时抛出异常 The trust relationship between the primary domain and the trusted domain failed。我们发现避免这种情况的一种简单可靠的方法是将 User 替换为 GenericPrincipal.

所需步骤:

(1) 创建一个 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) 注册您的过滤器。这可以在控制器级别或全局注册。通常,您将在 App_Start\FilterConfig.cs:

中执行此操作
public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new MyAuthorizationFilter(new AuthService()));
    }
}

(3) 在您的应用程序代码中使用提供的 GenericPrincipal 来回答有关用户身份和其他凭据的问题。例如在您的控制器方法中,您可以访问过滤器存储在 GenericPrincipal 中的用户名或任何其他 "claims"(例如电子邮件地址)。

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

因为您使用了内置机制来记录 Principal 角色,所以您可以使用 HttpContext.UserSystem.Threading.Thread.CurrentPrincipal 从任何地方访问用户详细信息。您还可以在控制器方法中使用 AuthorizeAttribute 来声明某些角色或用户可以使用哪些操作。例如

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

有关 ClaimsIdentity

的更多详细信息,请参阅 MSDN

希望对您有所帮助

-罗伯