2016-05-03 5 views
2

У меня есть приложение Owin. Я работаю в Mono, и я пытаюсь проверить подлинность на нем. Я использовал информацию о this page в качестве старта. Я быстро понял, что Owin Authentication использует некоторые конкретные библиотеки Windows. This question имел обходное решение для этого, хотя, как я думал, этого будет достаточно. Это не так.Моно с проверкой подлинности Owin

Следующий код генерирует исключение, описанное в другом вопросе (в другом месте, чем вопрос описывает (см. Комментарий в коде)). Если я попытаюсь прокомментировать материал, чтобы обнаружить ошибки, связанные с конвейером Owin, вызывается (из-за зависимостей). Если я достаточно прокомментирую, чтобы удалить это первое исключение, появится снова.

Неужели кто-то успешно смог установить аутентификацию в Owin (используя AspNet Identity) в Mono?

Запуск

public void Configure(IAppBuilder app) 
{ 
    // Add the AspNet Identity user manager to the Owin context 
    app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create); 

    // This was the first line to fail, but adding the AesDataProtectorProvider as 
    // described in the referred question fixed that 
    app.UseCookieAuthentication(new CookieAuthenticationOptions 
    { 
     AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, 
     LoginPath = new PathString("/login"), 
     Provider = new CookieAuthenticationProvider 
     { 
      OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
       validateInterval: TimeSpan.FromMinutes(30), 
       regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager)) 
     }, 
     TicketDataFormat = new SecureDataFormat<AuthenticationTicket>(
      DataSerializers.Ticket, 
      new AesDataProtectorProvider("myAuthKey"), 
      TextEncodings.Base64) 
    }); 

    // This causes an exception complaining that the Windows only assembly 
    // DpapiDataProtector can't be loaded, as described in the referred question 
    app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie); 

    // Set up the custom middleware as described in the first link 
    // Something inside this causes other exceptions. 
    app.Use(typeof(AuthMiddleware), app, new AuthOptions()); 
} 

AuthMiddleware

public class AuthMiddleware : AuthenticationMiddleware<AuthOptions> 
{ 
    public AuthMiddleware(OwinMiddleware next, IAppBuilder app, AuthOptions options) 
     : base(next, options) 
    { 
     if (string.IsNullOrEmpty(Options.SignInAsAuthenticationType)) 
     { 
      options.SignInAsAuthenticationType = app.GetDefaultSignInAsAuthenticationType(); 
     } 
     if (options.StateDataFormat == null) 
     { 
      var dataProtector = app.CreateDataProtector(typeof(AuthMiddleware).FullName, 
      options.AuthenticationType); 
      options.StateDataFormat = new PropertiesDataFormat(dataProtector); 
     } 
    } 

    protected override AuthenticationHandler<AuthOptions> CreateHandler() 
    { 
     return new AuthHandler(); 
    } 
} 

AuthOptions

public class AuthOptions : AuthenticationOptions 
{ 
    public AuthOptions() 
     : base("MyApp") 
    { 
     Description.Caption = "MyApp"; 
     // Where to redirect requests if not authenticated 
     CallbackPath = new PathString("/login");   AuthenticationMode = AuthenticationMode.Passive; 
    } 

    public PathString CallbackPath { get; set; } 
    public string SignInAsAuthenticationType { get; set; } 
    public ISecureDataFormat<AuthenticationProperties> StateDataFormat { get; set; } 
} 

AuthHandler

public class AuthHandler : AuthenticationHandler<AuthOptions> 
{ 
    protected override Task<AuthenticationTicket> AuthenticateCoreAsync() 
    { 
     var identity = new ClaimsIdentity(Options.SignInAsAuthenticationType); 
     var properties = Options.StateDataFormat.Unprotect(Request.Query["state"]); 
     return Task.FromResult(new AuthenticationTicket(identity, properties)); 
    } 

    protected override Task ApplyResponseChallengeAsync() 
    { 
     if (Response.StatusCode == 401) 
     { 
      var challenge = Helper.LookupChallenge(Options.AuthenticationType, Options.AuthenticationMode); 
      if (challenge != null) 
      { 
       var state = challenge.Properties; 
       if (string.IsNullOrEmpty(state.RedirectUri)) 
       { 
        state.RedirectUri = Request.Uri.ToString(); 
       } 
       var stateString = Options.StateDataFormat.Protect(state); 
       Response.Redirect(WebUtilities.AddQueryString(Options.CallbackPath.Value, "state", stateString)); 
      } 
     } 
     return Task.FromResult<object>(null); 
    } 

    public override async Task<bool> InvokeAsync() 
    { 
     Request.Environment.Add("Context", Context); 

     // If user is not logged in and tries to access any page that is not in 
     // the list of allowed pages, redirect to login page 
     if (Context.Authentication.User == null && 
      !Request.Path.ToString().StartsWith("/login")) 
     { 
      Response.Redirect(Options.CallbackPath.Value); 
      return true; 
     } 

     return false; 
    } 
} 

ответ

0

Очевидно, что код, представленный выше, включает в себя больше, чем необходимо для проверки подлинности Owin (и который не работает с Mono). Изучив и пробовав много перестановок, я уверен, что теперь у меня есть аутентификация в рабочем состоянии. Я не знаю, если это necessarilly является правильно состояние, но до тех пор, как он работает ...

Используя следующие настройки только страницы в списке разрешенных страниц (Controlled методом public override async Task<bool> InvokeAsync() в AuthHandler) доступны для пользователей, которые не вошли в систему. На странице входа я могу использовать ApplicationUserManager для входа в систему. После подписания все страницы, размещенные Owin, доступны.

Запуск

app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create); 

app.UseCookieAuthentication(new CookieAuthenticationOptions 
{ 
    AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, 
    LoginPath = new PathString("/login"), 
    Provider = new CookieAuthenticationProvider 
    { 
     OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
      validateInterval: TimeSpan.FromMinutes(30), 
      regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager)) 
    }, 
    TicketDataFormat = new SecureDataFormat<AuthenticationTicket>(
     DataSerializers.Ticket, 
     new AesDataProtectorProvider("myAuthKey"), 
     TextEncodings.Base64) 
}); 

app.Use(typeof(AuthMiddleware), app, new AuthOptions()); 

AuthMiddleware

public class AuthMiddleware : AuthenticationMiddleware<AuthOptions> 
{ 
    public AuthMiddleware(OwinMiddleware next, IAppBuilder app, AuthOptions options) 
     : base(next, options) 
    { 
     if (options.StateDataFormat == null) 
     { 
      options.StateDataFormat = new PropertiesDataFormat(new AesDataProtectorProvider("myAuthKey")); 
     } 
    } 

    protected override AuthenticationHandler<AuthOptions> CreateHandler() 
    { 
     return new AuthHandler(); 
    } 
} 

AuthHandler

public class AuthHandler : AuthenticationHandler<AuthOptions> 
{ 
    protected override Task<AuthenticationTicket> AuthenticateCoreAsync() 
    { 
     // This method never gets called in the current setup, 
     // but it is required because the compilation fails otherwise. 
     // Therefore only return an empty object. 
     return Task.FromResult<AuthenticationTicket>(null); 
    } 

    protected override Task ApplyResponseChallengeAsync() 
    { 
     if (Response.StatusCode == 401) 
     { 
      var challenge = Helper.LookupChallenge(Options.AuthenticationType, Options.AuthenticationMode); 
      if (challenge != null) 
      { 
       var state = challenge.Properties; 
       if (string.IsNullOrEmpty(state.RedirectUri)) 
       { 
        state.RedirectUri = Request.Uri.ToString(); 
       } 
       var stateString = Options.StateDataFormat.Protect(state); 
       Response.Redirect(WebUtilities.AddQueryString(Options.CallbackPath.Value, "state", stateString)); 
      } 
     } 
     return Task.FromResult<object>(null); 
    } 

    public override async Task<bool> InvokeAsync() 
    { 
     // If user is not logged in and tries to access any page that is not in 
     // the list of allowed pages, redirect to login page. 
     // Add any additional pages not protected by authentication here 
     if (Context.Authentication.User == null && 
      !Request.Path.ToString().StartsWith("/login")) 
     { 
      Response.Redirect(Options.CallbackPath.Value); 
      return true; 
     } 

     return false; 
    } 
} 
1

GitHub хранилище для демонстрации Mono WebAPI, проверки подлинности маркеров OAuth2 Bearer, AspNet.Identity + MySQL UserStore:

https://github.com/shturm/mono-webapi

enter image description here enter image description here

Несколько вещей, чтобы получить ясно:

  1. AspNet.Identity представляет собой набор интерфейсов (Microsoft.AspNet.Identity.Core) и их реализации (Microsoft.AspNet.Identity.EntityFramework/Owin), которые примерно описывают шаблон репозитория для сохранения счетов в базе данных.
  2. AspNet.Identity не выполняет аутентификацию/авторизацию. Он создает, сохраняет, обновляет, удаляет пользователей, заботясь о паролях.
  3. AspNet.Identity основные классы используются UserManager (от Microsoft.AspNet.Identity.Core) и SignInManger (от Microsoft.AspNet.Identity.Owin). SignInManager не требуется для выполнения какой-либо проверки подлинности OWIN.
  4. код вы вывесили строго Microsoft.Owin связаны и не имеет ничего общего с AspNet.Identity для ApplicationUserManager, которые в шаблонах Visual Studio расширяет Microsoft.AspNet.Identity.UserManager исключением.
0

Аутентификация в Owin использует async-конвейер, но Mono не поддерживает его.

Я делаю запрос на тягу для моно https://github.com/mono/mono/pull/3048. Выполняет синхронное выполнение асинхронного веб-api-стека.

Теперь вы можете использовать аутентификацию Owin с этим исправлением.

0

Я оставляю ответ, связанный с проблемой OP, но не обращаясь к нему, как ресурс для всех, кто не совершил переход к .NET Core.

В Mono, Mod-Mono и Apache мой опыт состоял в том, что функция Mono была неудачной, но с успехом выполнялась локально с VS.

Перед тем как исправить (startup.auth.cs)

app.UseCookieAuthentication(new CookieAuthenticationOptions 
{ 
    AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, 
    LoginPath = new PathString("/Account/Login"), 
    Provider = new CookieAuthenticationProvider 
    { 
     OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
      validateInterval: TimeSpan.FromMinutes(2), 
      regenerateIdentity: (manager, user) => AuthenticationService.RefreshIdentityAsync(manager, user)) 
    } 
}); 

я заметил в Dev Tools в Chrome (вкладка приложения), что куки остались, потому что был истечь дополнительно 2 недели в будущее.

Моим решением было отрегулировать время истечения срока действия файла cookie таким образом, чтобы оно совпало с интервалом проверки. Теперь клиент несет ответственность за выселение файлов cookie, а Mono не должен обрабатывать cookie при регенерации. Я понимаю, что это не общее решение, но для многих я уверен, что это достаточно хорошо.

После исправления

app.UseCookieAuthentication(new CookieAuthenticationOptions 
{ 
    AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, 
    LoginPath = new PathString("/Account/Login"), 
    ExpireTimeSpan = TimeSpan.FromMinutes(2), 
    SlidingExpiration = false, 
    Provider = new CookieAuthenticationProvider 
    { 
     OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
      validateInterval: TimeSpan.FromMinutes(2), 
      regenerateIdentity: (manager, user) => AuthenticationService.RefreshIdentityAsync(manager, user)) 
    } 
}); 
Смежные вопросы