Подтвердить что ты не робот

NancyFx и проверка подлинности Windows

Я хочу использовать NancyFx для веб-приложения в интрасети. Во всех документах и ​​форумах упоминаются только форма и обычная аутентификация. Кто-нибудь успешно использует Nancy с Windows Authentication?

Там также что-то называется Nancy.Authentication.Stateless, но я не вижу, что это делает (похоже, что он используется в Apis).

4b9b3361

Ответ 1

Я использовал это во внутреннем проекте недавно - мне это не очень нравится, и он связывает вас с хостом 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

Мне понадобилась аутентификация Windows с помощью Nancy для основного приложения для интрасети. Я использовал @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

    }
}

Вы используете его следующим образом:

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

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

}

Ответ 3

Использование Nancy с WindowsAuthentication обсуждается этот поток. Дамиан Хикки предоставил пример использования Nancy, размещенный OWin с 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

Ответ 4

Вы можете попытаться помочь мне закончить Nancy.Authentication.Ntlm. Это определенно пре-альфа. Я не знаю, как реализовать несколько вещей, основанных главным образом на моем ограниченном знании внутренних компонентов Нэнси.

В настоящее время код вызывает клиента, подтверждает ответ. Но я не смог сообщить клиенту об успехах этой операции.

Но я до сих пор работаю трудно. Действительно трудно.

И я был бы признателен за ваши комментарии и запросы на запросы, если они есть.

Ответ 5

Стоя на полках гигантов, я внедрил это таким образом, чтобы позволить аутентификации быть издеваемым для тестирования

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:

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

Реализация это немного грязная, так как вам нужно, чтобы IWindowsAuthenticationProvided вводился в каждый модуль

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