ASP.NET MVC中的ServiceStack.NET Windows身份验证(NTLM)

MVC*_*ble 20 c# windows-authentication servicestack asp.net-mvc-4

如何在ASP.NET MVC4上构建的ServiceStack项目中实现Windows身份验证?

我开始使用添加的全局请求过滤器AppHost:

private void ConfigureAuth(Funq.Container container)
{
    this.RequestFilters.Add((httpReq, httpResp, requestDto) =>
    {
        var user = HttpContext.Current.User.Identity;
        if (!user.IsAuthenticated ||
            !user.Name.Contains(_myTestUser)) //todo: check username here in database (custom logic) if it has access to the application
            httpResp.ReturnAuthRequired();
    });
}
Run Code Online (Sandbox Code Playgroud)

这将打开一个登录对话框,如果输入正确(用户名存在且输入了有效密码,并且myTestUser设置为此密码),则会产生成功的响应.如果有任何错误,将再次显示登录对话框. - 这对我来说听起来不错.但在第二个登录窗口中重新输入正确的用户后,它将停止工作.该对话框再次打开,如果它再次不正确.过滤器函数内没有遇到断点.

知道是什么原因引起的吗?

这就是我在web.config中添加的内容:

<authentication mode="Windows"/>
<authorization>
  <deny users="?" /> <!--only allow authenticated users-->
</authorization>
Run Code Online (Sandbox Code Playgroud)

我想完全锁定网站并仅使用其特定权限(角色)启用对数据库中指定Windows用户的访问.我需要实现自定义逻辑来访问"用户和角色列表".也许在MVC4/ASP.NET中有另一种方法可以做到这一点?

小智 12

Windows Intranet的ServiceStack自定义身份验证

我整天都在反对这一点,并提出以下建议.

用例:

您使用Windows身份验证在企业Intranet上.您在web.config中设置了身份验证模式="Windows",就是这样!

你的策略是这样的:

  1. 你不知道用户是谁,因为他们不在你的用户表或ActiveDirectory组或其他什么.在这种情况下,您将赋予它们"guest"的角色并相应地修剪UI.也许给他们一个电子邮件链接来请求访问.

  2. 您的用户列表中包含该用户,但尚未为其分配角色.因此,给他们扮演"用户"的角色,并如上所述修剪UI.也许他们可以看到他们的东西,但没有别的.

  3. 用户位于列表中,并已分配角色.最初,您将通过手动更新数据库中的UserAuth表来分配角色.最终,您将获得为授权用户执行此操作的服务.

那么让我们来看看代码.

服务器端

在ServiceStack Service层中,我们根据https://github.com/ServiceStack/ServiceStack/wiki/Authentication-and-authorization创建自定义凭据授权提供程序

      public class CustomCredentialsAuthProvider : CredentialsAuthProvider
        {
            public override bool TryAuthenticate(IServiceBase authService, string userName, string password)
            {
                //NOTE: We always authenticate because we are always a Windows user! 
                // Yeah, it's an intranet  
                return true;
            }

            public override void OnAuthenticated(IServiceBase authService, IAuthSession session, IOAuthTokens tokens, Dictionary<string, string> authInfo)
            {

                // Here is why we set windows authentication in web.config
                var userName = HttpContext.Current.User.Identity.Name;

                //  Strip off the domain
                userName = userName.Split('\\')[1].ToLower();

                // Now we call our custom method to figure out what to do with this user
                var userAuth = SetUserAuth(userName);

                // Patch up our session with what we decided
                session.UserName = userName;
                session.Roles = userAuth.Roles;            

                // And save the session so that it will be cached by ServiceStack 
                authService.SaveSession(session, SessionExpiry);
            }

        }
Run Code Online (Sandbox Code Playgroud)

这是我们的自定义方法:

     private UserAuth SetUserAuth(string userName)
            {
                // NOTE: We need a link to the database table containing our user details
                string connStr = ConfigurationManager.ConnectionStrings["YOURCONNSTRNAME"].ConnectionString;
                var connectionFactory = new OrmLiteConnectionFactory(connStr, SqlServerDialect.Provider);

                // Create an Auth Repository
                var userRep = new OrmLiteAuthRepository(connectionFactory);

                // Password not required. 
                const string password = "NotRequired";

                // Do we already have the user? IE In our Auth Repository
                UserAuth userAuth = userRep.GetUserAuthByUserName(userName);

                if (userAuth == null ){ //then we don't have them}

                // If we don't then give them the role of guest
                userAuth.Roles.Clear();
                userAuth.Roles.Add("guest")

                // NOTE: we are only allowing a single role here               

                // If we do then give them the role of user
                // If they are one of our team then our administrator have already given them a role via the setRoles removeRoles api in ServiceStack
               ...

                // Now we re-authenticate out user
                // NB We need userAuthEx to avoid clobbering our userAuth with the out param
                // Don't you just hate out params?

                // And we re-authenticate our reconstructed user
                UserAuth userAuthEx;
                var isAuth = userRep.TryAuthenticate(userName, password, out userAuthEx);
                return userAuth;
            }
Run Code Online (Sandbox Code Playgroud)

在appHost Configure中,在函数末尾添加以下ResponseFilters

    ResponseFilters.Add((request, response, arg3) => response.AddHeader("X-Role",request.GetSession(false).Roles[0]));
    ResponseFilters.Add((request, response, arg3) => response.AddHeader("X-AccountName", request.GetSession(false).UserName));
Run Code Online (Sandbox Code Playgroud)

这会向客户端发送一些额外的标头,以便我们可以根据用户的角色修剪UI.

客户端

在客户端,当我们向服务器发出第一个请求时,我们按照自定义身份验证的要求POST一个UserName和Password.两者都设置为"NotRequired",因为我们将通过HttpContext.Current.User.Identity.Name知道用户在服务器端的用户.

以下使用AngularJS进行AJAX通信.

    app.run(function($templateCache, $http, $rootScope) {

        // Authenticate and get X-Role and X-AccountName from the response headers and put it in $rootScope.role

        // RemeberMe=true means that the session will be cached 
        var data={"UserName" : "NotRequired", "Password" : "NotRequired", "RememberMe": true };

        $http({ method : 'POST', url : '/json/reply/Auth', data : data }).
            success(function (data, status, headers, config) {
            // We stash this in $rootScope for later use!
                $rootScope.role = headers('X-Role');
                $rootScope.accountName = headers('X-AccountName');
                console.log($rootScope.role);
                console.log($rootScope.role);
            }).
            error(function (data, status, headers, config) {
                // NB we should never get here because we always authenticate
                toastr.error('Not Authenticated\n' + status, 'Error');
            });
    };
Run Code Online (Sandbox Code Playgroud)