2012-11-16 13 views
19

イントラネットWebアプリケーションにNancyFxを使用したいと思います。すべてのドキュメントとフォーラムには、フォームと基本認証のみが記載されています。誰でもWindows認証でナンシーを正常に使用できますか?NancyFxとWindows認証

Nancy.Authentication.Statelessという名前のものもありますが、それが何であるかはわかりません(Apisで使用するように見えます)。

答えて

8

私は最近、社内プロジェクトでこれを使用 - 私は実際にそれ好きではない、それはホスティングASP.NETにあなたを結び付け、それは仕事をした:

namespace Blah.App.Security 
{ 
    using System; 
    using System.Collections.Generic; 
    using System.Linq; 
    using System.Security.Principal; 
    using System.Web; 

    using Nancy; 

    public static class SecurityExtensions 
    { 
     public static string CurrentUser 
     { 
      get 
      { 
       return GetIdentity().Identity.Name; 
      } 
     } 

     public static bool HasRoles(params string[] roles) 
     { 
      if (HttpContext.Current != null && HttpContext.Current.Request.IsLocal) 
      { 
       return true; 
      } 

      var identity = GetIdentity(); 

      return !roles.Any(role => !identity.IsInRole(role)); 
     } 

     public static void RequiresWindowsAuthentication(this NancyModule module) 
     { 
      if (HttpContext.Current != null && HttpContext.Current.Request.IsLocal) 
      { 
       return; 
      } 

      module.Before.AddItemToEndOfPipeline(
       new PipelineItem<Func<NancyContext, Response>>(
        "RequiresWindowsAuthentication", 
        ctx => 
         { 
          var identity = GetIdentity(); 

          if (identity == null || !identity.Identity.IsAuthenticated) 
          { 
           return HttpStatusCode.Forbidden; 
          } 

          return null; 
         })); 
     } 

     public static void RequiresWindowsRoles(this NancyModule module, params string[] roles) 
     { 
      if (HttpContext.Current != null && HttpContext.Current.Request.IsLocal) 
      { 
       return; 
      } 

      module.RequiresWindowsAuthentication(); 

      module.Before.AddItemToEndOfPipeline(new PipelineItem<Func<NancyContext, Response>>("RequiresWindowsRoles", GetCheckRolesFunction(roles))); 
     } 

     private static Func<NancyContext, Response> GetCheckRolesFunction(IEnumerable<string> roles) 
     { 
      return ctx => 
       { 
        var identity = GetIdentity(); 

        if (roles.Any(role => !identity.IsInRole(role))) 
        { 
         return HttpStatusCode.Forbidden; 
        } 

        return null; 
       }; 
     } 

     private static IPrincipal GetIdentity() 
     { 
      if (System.Web.HttpContext.Current != null) 
      { 
       return System.Web.HttpContext.Current.User; 
      } 

      return new WindowsPrincipal(WindowsIdentity.GetCurrent()); 
     } 

     public static Func<NancyContext, Response> RequireGroupForEdit(string group) 
     { 
      return ctx => 
       { 
        if (ctx.Request.Method == "GET") 
        { 
         return null; 
        } 

        return HasRoles(group) ? null : (Response)HttpStatusCode.Forbidden; 
       }; 
     } 
    } 
} 

これは、すべてのセキュリティチェックをバイパスそれがローカルから来ている場合(テスト用)、これはおそらく悪い考えですが、ファイアウォールの背後にあるので、これは問題ではありません。

は、あなたがそれをそのまま使用することをお勧めではないだろうが、正しい方向にあなたを指している可能性があります:)

2

あなたは私がNancy.Authentication.Ntlmを終了助けるために試みることができます。これは間違いなくプレアルファです。私はナンシー内部の限られた知識に主に基づいていくつかを実装する方法を知らない。

現在、コードはクライアントに挑戦し、答えを検証します。しかし、私はこの操作の成功を知らせるのに失敗しました。

しかし、私はまだ努力しています。とても大変。

あなたのコメントとプルリクエストがあれば、それを感謝します。

17

基本的なイントラネットアプリケーションでは、Nancyを使用したWindows認証が必要でした。私は@ Steven Robbinsの答えを出発点として使用しましたが、私たちが必要としなかったものを取り除き、NancyContext.CurrentUserプロパティの人口を追加しました。あなたはこのようにそれを使用

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Security.Principal; 
using System.Web; 
using Nancy; 
using Nancy.Security; 

namespace YourNamespace 
{ 
    /// <summary> 
    /// Extensions for Nancy that implement Windows Authentication. 
    /// </summary> 
    public static class WindowsAuthenticationExtensions 
    { 
     private class WindowsUserIdentity : IUserIdentity 
     { 
      private string _userName; 

      public WindowsUserIdentity(string userName) 
      { 
       _userName = userName; 
      } 

      #region IUserIdentity 

      IEnumerable<string> IUserIdentity.Claims 
      { 
       get { throw new NotImplementedException(); } 
      } 

      string IUserIdentity.UserName 
      { 
       get { return _userName; } 
      } 

      #endregion 
     } 

     #region Methods 

     /// <summary> 
     /// Forces the NancyModule to require a user to be Windows authenticated. Non-authenticated 
     /// users will be sent HTTP 401 Unauthorized. 
     /// </summary> 
     /// <param name="module"></param> 
     public static void RequiresWindowsAuthentication(this NancyModule module) 
     { 
      if (HttpContext.Current == null) 
       throw new InvalidOperationException("An HttpContext is required. Ensure that this application is running under IIS."); 

      module.Before.AddItemToEndOfPipeline(
       new PipelineItem<Func<NancyContext, Response>>(
        "RequiresWindowsAuthentication", 
        context => 
        { 
         var principal = GetPrincipal(); 

         if (principal == null || !principal.Identity.IsAuthenticated) 
         { 
          return HttpStatusCode.Unauthorized; 
         } 

         context.CurrentUser = new WindowsUserIdentity(principal.Identity.Name); 

         return null; 
        })); 
     } 

     private static IPrincipal GetPrincipal() 
     { 
      if (HttpContext.Current != null) 
      { 
       return HttpContext.Current.User; 
      } 

      return new WindowsPrincipal(WindowsIdentity.GetCurrent()); 
     } 

     #endregion 

    } 
} 

:巨人のsholdersに

public class YourModule : NancyModule 
{ 
    public YourModule() 
    { 
     this.RequiresWindowsAuthentication(); 

     Get["/"] = parameters => 
      { 
       //... 
      }; 
    } 

}

+0

ありがとう、これは私を助けました。モジュールレベルではなく要求ごとにどのように修正することができますか?または、各ルート内の個々の申し立てを確認するだけですか? – mjbates7

+0

ルートハンドラの内部に[this.RequiresAuthentication()](https://stackoverflow.com/questions/12185257/nancyfx-authentication-per-route)を追加することができます。 –

+1

あなたは 'System.Web'と結びついているので'OWIN'の自己ホスティングの場合はあまり役に立ちません。私の要件を満たすのはCodeFoxの答えです。 – MaYaN

2

立ち、私は認証がテストのために嘲笑することができるようにするには、この方法でそれを実装しました

using System; 
using System.Collections.Generic; 
using Nancy; 
using Nancy.Security; 

namespace Your.Namespace 
{ 
    /// <summary> 
    /// Extensions for Nancy that implement Windows Authentication. 
    /// </summary> 
    public static class WindowsAuthenticationExtensions 
    { 
     private class WindowsUserIdentity : IUserIdentity 
     { 
      private readonly string _userName; 

      public WindowsUserIdentity(string userName) 
      { 
       _userName = userName; 
      } 

      #region IUserIdentity 

      IEnumerable<string> IUserIdentity.Claims 
      { 
       get { throw new NotImplementedException(); } 
      } 

      string IUserIdentity.UserName 
      { 
       get { return _userName; } 
      } 

      #endregion 
     } 

     #region Methods 

     /// <summary> 
     /// Forces the NancyModule to require a user to be Windows authenticated. Non-authenticated 
     /// users will be sent HTTP 401 Unauthorized. 
     /// </summary> 
     /// <param name="module"></param> 
     /// <param name="authenticationProvider"></param> 
     public static void RequiresWindowsAuthentication(this NancyModule module, IWindowsAuthenticationProvider authenticationProvider) 
     { 
      if (!authenticationProvider.CanAuthenticate) 
       throw new InvalidOperationException("An HttpContext is required. Ensure that this application is running under IIS."); 

      module.Before.AddItemToEndOfPipeline(
       new PipelineItem<Func<NancyContext, Response>>(
        "RequiresWindowsAuthentication", 
        context => 
        { 
         var principal = authenticationProvider.GetPrincipal(); 

         if (principal == null || !principal.Identity.IsAuthenticated) 
         { 
          return HttpStatusCode.Unauthorized; 
         } 

         context.CurrentUser = new WindowsUserIdentity(principal.Identity.Name); 

         return null; 
        })); 
     } 

     #endregion 

    } 
} 

IWindowsAuthenticationProvider:

using System.Security.Principal; 

namespace Your.Namespace 
{ 
    public interface IWindowsAuthenticationProvider 
    { 
     bool CanAuthenticate { get; } 
     IPrincipal GetPrincipal(); 
    } 
} 

WindowsAuthenticationProvider:あなたはIWindowsAuthenticationProvidedはWindowsAuthenticationがthis threadで議論されてナンシーを使用して、すべてのモジュール

public DefaultModule(IWindowsAuthenticationProvider authenticationProvider) 
     { 
      this.RequiresWindowsAuthentication(authenticationProvider); 
      Get["/"] = _ => "Hello World"; 
     } 
16

に注入必要があるとして、それを実装する

using System.Security.Principal; 
using System.Web; 

namespace Your.Namespace 
{ 
    public class WindowsAuthenticationProvider : IWindowsAuthenticationProvider 
    { 
     public bool CanAuthenticate 
     { 
      get { return HttpContext.Current != null; } 
     } 

     public IPrincipal GetPrincipal() 
     { 
      if (HttpContext.Current != null) 
      { 
       return HttpContext.Current.User; 
      } 

      return new WindowsPrincipal(WindowsIdentity.GetCurrent()); 
     } 
    } 
} 

は少し厄介です。 Damian Hickeyはexample of using Nancy, hosted by OWin with WindowsAuthenticationを提供しています。

は、私は少し(廃止NancyOwinHostを削除する)コードを変更した:

namespace ConsoleApplication1 
{ 
    using System; 
    using System.Net; 
    using System.Security.Principal; 
    using Microsoft.Owin.Hosting; 
    using Nancy; 
    using Nancy.Owin; 
    using Owin; 

    internal static class Program 
    { 
     private static void Main(string[] args) 
     { 
      using (WebApp.Start<Startup>("http://localhost:9000")) 
      { 
       Console.WriteLine("Press any key to quit."); 
       Console.ReadKey(); 
      } 
     } 
    } 

    internal sealed class Startup 
    { 
     public void Configuration(IAppBuilder app) 
     { 
      var listener = (HttpListener) app.Properties["System.Net.HttpListener"]; 
      listener.AuthenticationSchemes = AuthenticationSchemes.IntegratedWindowsAuthentication; 

      app.UseNancy(); 
     } 
    } 

    public sealed class MyModule : NancyModule 
    { 
     public MyModule() 
     { 
      Get[""] = _ => 
      { 
       var env = this.Context.GetOwinEnvironment(); 
       var user = (IPrincipal) env["server.User"]; 

       return "Hello " + user.Identity.Name; 
      }; 
     } 
    } 
} 

特別な感謝はダミアンに行きます!


例では、次のNuGetパッケージを必要とします。

  • Microsoft.Owin.Host.HttpListener
  • Microsoft.Owin.Hosting
  • Microsoft.Owin
  • Nancy
  • Nancy.Owin
  • Owin
+0

ありがとう、私の日を救った。 – MaYaN

+0

NTMLでも正常に動作します。 – Thomas