ASP.Net MVC Custom Authentication - PullRequest
       7

ASP.Net MVC Custom Authentication

3 голосов
/ 19 мая 2011

У меня есть веб-приложение Asp.Net MVC, которое находится внутри веб-сайта, все еще в значительной степени управляемого delphi В настоящее время безопасность управляется delphi, который создает файлы cookie.

Было решено аутентифицировать пользователей в приложении ASP.Net, извлекая данные cookie и передавая их в импортированную DLL-библиотеку Delphi, которая возвращает значение true или false в зависимости от того, является ли пользователь действительным.

Я планировал использовать проверку подлинности с помощью форм, но вместо того, чтобы перенаправлять пользователя на форму, вместо этого вызвать обертку delphi и, в случае успеха, перенаправить пользователя на исходный URL-адрес. Это дает преимущество, заключающееся в том, что при переносе безопасности на .Net инфраструктура аутентификации уже будет существовать, просто потребуется изменить реализацию.

public ActionResult LogOn(SecurityCookies model, string returnUrl)
    {
        try
        {
            if (model != null)
            {
                Log.DebugFormat("User login: Id:{0}, Key:{1}", model.UserId, model.Key);
                if (authenticator.UserValid(model.UserId, model.Key, 0))
                {
                    FormsService.SignIn(model.UserId, false);
                    return Redirect(returnUrl);
                }
            }
...

Обратите внимание, что SecurityCookies генерируются пользовательским классом привязки из файла cookie, сгенерированного delphi - это хорошо работает.

Звонок в DLL Delphi также работает нормально.

Проблема, которую я должен преодолеть, заключается в том, что почти все вызовы приложения .Net являются запросами ajax. Однако, когда пользователь не вошел в систему, браузер делает 3 вызова из-за перенаправлений: 1) Оригинальный запрос ajax 2) Перенаправить в ~ / Account / Logon (код выше) 3) Перенаправить обратно на исходный запрос ajax

Хотя отслеживание ответов, отправленных обратно клиенту, показывает, что на шаге 3 возвращаются правильные данные, в целом процесс завершается неудачей по еще не определенной причине. Простое нажатие кнопки «Обновить» на клиенте работает, потому что теперь пользователь проходит проверку подлинности, а перенаправление в ~ / account / Logon не происходит.

Обратите внимание, что мой клиентский код jQuery выглядит следующим образом: $ .getJSON (requestString, function (data) { // сделать что-то с данными });

Есть ли способ изменить процесс проверки подлинности с помощью форм, чтобы вместо перенаправления на URL-адрес, когда пользователь не прошел проверку подлинности, вместо этого я мог запустить другой код? Мне бы хотелось, чтобы аутентификация была полностью невидимой для браузера пользователя.

Ответы [ 3 ]

8 голосов
/ 19 мая 2011

Если вы хотите аутентифицировать запрос, место для этого находится в global.asax.cs путем определения метода Application_AuthenticateRequest.Здесь вы можете прочитать пользовательские куки с импортированной библиотекой delphi и установить Context.User.Вся авторизация в asp.net основана на пользователе, установленном в HttpContext.Пример реализации метода Application_AuthenticateRequest:

protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
    HttpCookie authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
    if(authCookie != null)
    {
        //Extract the forms authentication cookie
        FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
        // Create an Identity object
        //CustomIdentity implements System.Web.Security.IIdentity
        CustomIdentity id = GetUserIdentity(authTicket.Name);
        //CustomPrincipal implements System.Web.Security.IPrincipal
        CustomPrincipal newUser = new CustomPrincipal();
        Context.User = newUser;
    }
}

Если файл cookie недействителен, вы не установите пользователя в контексте.

Затем вы можете создать BaseController, которыйвсе ваши контроллеры унаследуют от этих проверок, аутентифицирован ли предоставленный в контексте пользователь.Если пользователь не аутентифицирован, вы можете вернуть HttpUnauthorizedResult.

public class BaseController : Controller
{
    protected override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (User == null || (User != null && !User.Identity.IsAuthenticated))
        {
           filterContext.Result = new HttpUnauthorizedResult();
        }
        else
        {
            // Call the base
            base.OnActionExecuting(filterContext);
        }
    }
}

И в вашем файле web.config:

<authentication mode="None"/>

, поскольку вы не хотите, чтобы запрос был перенаправлен настраница входа.

1 голос
/ 19 мая 2011

Я собираюсь ответить на часть этого конкретного вопроса

Есть ли способ изменения форм Процесс аутентификации, так что вместо перенаправления на URL, когда пользователь не проверено, я могу запустить некоторые другой код вместо? Я бы хотел тот факт что аутентификация состоялась быть полностью невидимым для пользователя браузер.

Нет, нет. Я написал систему входа в систему, которая похожа на вашу, поскольку она построена поверх аутентификации форм, а тот факт, что нет точки расширения, сделал ее полноценной PITA для записи.

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

internal static bool IsFormsAuthenticationLogin(HttpResponseBase response)
{
    if (!response.IsRequestBeingRedirected) return false;
    if (string.IsNullOrWhiteSpace(response.RedirectLocation)) return false;

    Uri formsAuthUri;
    try
    {
        formsAuthUri = new Uri(FormsAuthentication.LoginUrl);
    }
    catch (Exception ex)
    {
        throw new XifCriticalException("Could not construct formsAuthUri", ex);
    }


    Uri redirctUri;
    try
    {
        redirctUri = new Uri(response.RedirectLocation, UriKind.RelativeOrAbsolute);
    }
    catch (Exception ex)
    {
        throw new XifCriticalException("Could not construct redirctUri", ex);
    }

    try
    {
        //Check if the request was redirected by Forms Auth
        bool isFormsAuthenticationLogin = redirctUri.IsAbsoluteUri &&
                                            redirctUri.Host == formsAuthUri.Host
                                            && redirctUri.PathAndQuery.Contains(formsAuthUri.PathAndQuery); 

        return isFormsAuthenticationLogin;
    }
    catch (Exception ex)
    {
        throw new XifCriticalException("Could not construct isFormsAuthenticationLogin", ex);
    }
}

Еще одно замечание: чтобы использовать этот код в MVC3, вам также может потребоваться указать настройки приложения

 <add key="enableSimpleMembership" value="false" />
 <add key="autoFormsAuthentication" value="false" />
0 голосов
/ 19 мая 2011

Пара вещей.

Во-первых, поскольку вы, очевидно, находитесь в действии контроллера, вы должны заменить

Server.Transfer(returnUrl, true);

на

return Redirect(returnUrl);

Во-вторых, я обычнопредпочитайте , а не использовать вызовы ajax для аутентификации.Пользователи должны явно перейти из состояний без проверки подлинности в состояния с проверкой подлинности.

В-третьих, если вы должны выполнять вызовы ajax там, где вы обычно делаете перенаправления, вы можете сделать одну из двух вещей.В вашем контроллере вы можете определить, что это ajax-запрос, вызвав метод расширения IsAjaxRequest () (возвращает true, если он есть) и добавив другой результат, если это ajax-запрос.Во-вторых, если вы вернете Redirect, он вернет клиенту HTTP-перенаправление, которое клиентский код Ajax должен уметь читать и отвечать на него (например, читая Location, а затем выполняя ajax-выборку).Опять же, я не рекомендую этот курс, но это возможно.

Наконец, как полный левый поворот ... Вы рассматривали возможность оставить формы аутентификации в одиночку и вместо этого использовать пользовательский MembershipProvider?Вы можете использовать это для проверки членства через Delphi, а затем установить клиентские куки-файлы, используя обычные объекты FormsAuth, как это делается в примере AccountController в MVC.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...