20

ASP.NET MVC4 でビルドされた ServiceStack プロジェクトに Windows 認証を実装する方法は?

に追加されたグローバル Request-Filter から始めました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();
    });
}

これにより、ログイン ダイアログが開きます。正しく入力された場合 (ユーザー名が存在し、有効なパスワードが入力され、myTestUserがこれに設定されている場合)、正常な応答が返されます。何か問題がある場合は、ログイン ダイアログが再度表示されます。-- それはいいですね。しかし、2 回目のログイン ウィンドウで正しいユーザーを再入力すると、機能しなくなります。もう一度間違っている場合は、ダイアログが再び開きます。フィルター関数内でブレークポイントにヒットしません。

何がこれを引き起こす可能性がありますか?

それは私がweb.configに追加したものです:

<authentication mode="Windows"/>
<authorization>
  <deny users="?" /> <!--only allow authenticated users-->
</authorization>

Web サイトを完全にロックし、データベース内の特定の Windows ユーザーが特定の権限 (ロール) でのみアクセスできるようにしたいと考えています。「ユーザーとロールのリスト」にアクセスするには、カスタム ロジックを実装する必要があります。MVC4/ASP.NET でこれを行う別の方法があるのではないでしょうか?

4

4 に答える 4

13

Windows イントラネットの ServiceStack カスタム認証

私は一日中これに頭を悩ませており、次のことを思いつきました。

最初のユースケース:

Windows 認証を使用して企業イントラネットを使用しています。web.config で authentication mode="Windows" を設定すれば完了です。

あなたの戦略は次のとおりです。

  1. ユーザーのテーブルや ActiveDirectory グループなどに含まれていないため、ユーザーが誰であるかはわかりません。この場合、「ゲスト」の役割を与え、それに応じて UI をトリムします。アクセスをリクエストするための電子メール リンクを提供することもできます。

  2. ユーザーのリストにユーザーがいますが、役割が割り当てられていません。そのため、「ユーザー」の役割を与えて、上記のように UI をトリムします。たぶん彼らは自分のものを見ることができますが、他には何もありません.

  3. ユーザーはリストにあり、役割が割り当てられています。最初に、データベースの UserAuth テーブルを手動で更新してロールを割り当てます。最終的には、許可されたユーザーに対してこれを行うサービスができます。

それでは、コードに行きましょう。

サーバ側

ServiceStack サービス レイヤーでは、 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);
            }

        }

カスタムメソッドは次のとおりです。

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

appHost 構成で、関数の最後に次の 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));

これにより、いくつかの追加ヘッダーがクライアントに送信され、ユーザーの役割に従って UI をトリミングできるようになります。

クライアント側

クライアント側では、サーバーに最初のリクエストを送信するときに、カスタム認証で必要な UserName と Password を POST します。HttpContext.Current.User.Identity.Name を介してサーバー側でユーザーが誰であるかがわかるため、両方とも「NotRequired」に設定されています。

以下では、AJAX 通信に AngularJS を使用しています。

    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');
            });
    };
于 2013-03-27T20:35:49.530 に答える
3

バージョン 4.0.21 以降は、おそらく注目に値するでしょう。ここに示すように、Windows 認証プロバイダーが実装されています: https://github.com/ServiceStack/ServiceStack/blob/master/release-notes.md#windows-auth-provider-for-aspnet

于 2014-06-01T12:33:54.673 に答える
1

構成ファイルの system.web 要素で偽装を有効にしましたか?

<identity impersonate="true"/>

何かが制限されたリソースにアクセスしようとすると、2 番目の失敗につながる可能性があります。

どのユーザーがシステムにアクセスできるかを識別するカスタム ロジックを実装したいとおっしゃいました。私はそれを仮定します

<allow roles="DomainName\WindowsGroup" />
<deny users="*" />

十分ではありません。もしそうなら素晴らしいですが、それ以外の場合は、役立つカスタム ロール プロバイダーを実装することもできます。これには、Windows の代わりにフォーム認証を使用する必要がありますが、必ずしも Windows 資格情報を使用してユーザーを認証できないという意味ではありません。

于 2013-03-19T16:29:18.440 に答える