2014-11-06 88 views
14

Mogę być zbyt skomplikowana, ale mamy wewnętrzne ASP.NET MVC5 SPA z AngularJS przy użyciu uwierzytelniania Windows. Ta aplikacja ma bazę danych SQL back-end, która ma tabelę użytkowników, zawierającą nazwy ich kont i ich odpowiednie role w aplikacji. Będziemy nawiązywać połączenia z inną aplikacją Web API, która ma również włączone uwierzytelnianie systemu Windows.Aplikacja ASP.NET MVC5/AngularJS/Web API korzystająca z uwierzytelniania systemu Windows i OWIN

Próbowałem przeprowadzić badania dotyczące obsługi autoryzacji za pomocą OWIN, ale nie znalazłem konkretnych przykładów dotyczących uwierzytelniania OWIN i Windows. Wszystko, co się pojawi, wykorzystuje uwierzytelnianie za pomocą nazwy użytkownika i hasła.

Jak mogę korzystać z OWIN i Windows Auth dla mojej aplikacji? Oto przykład mojej klasy OAuthAuthorizationServerProvider.

public class SimpleAuthorizationServerProvider : OAuthAuthorizationServerProvider 
{ 
    public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context) 
    { 
     context.Validated(); 
     return; 
    } 

    public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) 
    { 
     context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" }); 

     var container = UnityHelper.GetContainerInstance("***"); 
     var securityHelper = container.Resolve<ISecurityHelper>(); 

     User currentUser = securityHelper.GetCurrentUser(); // Validates user based on HttpContext.Current.User 
     if (currentUser == null) 
     { 
      context.SetError("invalid_grant", "The user could not be found."); 
      return; 
     } 

     var identity = new ClaimsIdentity(context.Options.AuthenticationType); 
     identity.AddClaim(new Claim("sub", currentUser.AccountName)); 
     identity.AddClaim(new Claim("role", "user")); 

     context.Validated(identity); 
    } 
} 

UPDATE: Ups, zapomniałem podać więcej informacji na temat tego, co chcemy osiągnąć. Jeśli to możliwe, chcielibyśmy użyć biletów uwierzytelniających na okaziciela, abyśmy nie musieli wyszukiwać użytkownika i jego ról za każdym razem, gdy nawiążemy połączenie z metodą api web.

UPDATE 2: Na wniosek Andrzeja, poniżej jest wersja TLDR mojej klasie _securityHelper, a konkretnie sposobu GetCurrentUser(). Zauważysz, że ja próbuje zadzwonić:

HttpContext.Current.GetOwinContext().Request.User.Identity.Name 

To zawsze wraca zerowy dla Użytkownika.

public class SecurityHelper : ISecurityHelper 
{ 
    private readonly ISecurityGroupController _securityGroupController; 
    private readonly IUserController _userController; 
    private readonly IEmployeeController _employeeController; 
    private readonly IFieldPermissionController _fieldPermissionController; 
    private readonly IOACController _oacController; 

    public SecurityHelper(ISecurityGroupController securityGroupController, 
     IUserController userController, 
     IEmployeeController employeeController, 
     IFieldPermissionController fieldPermissionController, 
     IOACController oacController) 
    { 
     _securityGroupController = securityGroupController; 
     _userController = userController; 
     _employeeController = employeeController; 
     _fieldPermissionController = fieldPermissionController; 
     _oacController = oacController; 
    } 

    // ... other methods 

    public User GetCurrentUser() 
    { 
     User user = _userController.GetByAccountName(HttpContext.Current.GetOwinContext().Request.User.Identity.Name); 
     if (user != null) 
     { 
      List<OAC> memberships = _oacController.GetMemberships(user.SourceId).ToList(); 
      if (IsTestModeEnabled() && ((user.OACMemberships != null && user.OACMemberships.Count == 0) || user.OACMemberships == null)) 
      { 
       user.OACMemberships = memberships; 
      } 
      else if (!IsTestModeEnabled()) 
      { 
       user.OACMemberships = memberships; 
      } 
     } 

     return user; 
    } 
} 

Odpowiedz

5

Ta seria artykuł byłby dobrym miejscem do rozpoczęcia: http://bitoftech.net/2014/06/01/token-based-authentication-asp-net-web-api-2-owin-asp-net-identity/

zauważyć, byłby następujący kod, który zasadniczo przechowuje okaziciela token w pamięci lokalnej i przywiązuje go do nagłówków. Oczywiście jest o wiele więcej niż to, w tym formularze i rzeczywisty system uwierzytelniania serwera, ale powinno to dać dobry początek.

składnik serwera:

public class Startup 
{ 
    public void Configuration(IAppBuilder app) 
    { 
     ConfigureOAuth(app); 
    //Rest of code is here; 
    } 

    public void ConfigureOAuth(IAppBuilder app) 
    { 
     OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions() 
     { 
      AllowInsecureHttp = true, 
      TokenEndpointPath = new PathString("/token"), 
      AccessTokenExpireTimeSpan = TimeSpan.FromDays(1), 
      Provider = new SimpleAuthorizationServerProvider() 
     }; 

     // Token Generation 
     app.UseOAuthAuthorizationServer(OAuthServerOptions); 
     app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions()); 

    } 
} 

i następujący kod po stronie klienta:

'use strict'; 
app.factory('authService', ['$http', '$q', 'localStorageService', function ($http, $q, localStorageService) { 

    var serviceBase = 'http://ngauthenticationapi.azurewebsites.net/'; 
    var authServiceFactory = {}; 

    var _authentication = { 
     isAuth: false, 
     userName : "" 
    }; 

    var _saveRegistration = function (registration) { 

     _logOut(); 

     return $http.post(serviceBase + 'api/account/register', registration).then(function (response) { 
      return response; 
     }); 

    }; 

    var _login = function (loginData) { 

     var data = "grant_type=password&username=" + loginData.userName + "&password=" + loginData.password; 

     var deferred = $q.defer(); 

     $http.post(serviceBase + 'token', data, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }).success(function (response) { 

      localStorageService.set('authorizationData', { token: response.access_token, userName: loginData.userName }); 

      _authentication.isAuth = true; 
      _authentication.userName = loginData.userName; 

      deferred.resolve(response); 

     }).error(function (err, status) { 
      _logOut(); 
      deferred.reject(err); 
     }); 

     return deferred.promise; 

    }; 

    var _logOut = function() { 

     localStorageService.remove('authorizationData'); 

     _authentication.isAuth = false; 
     _authentication.userName = ""; 

    }; 

    var _fillAuthData = function() { 

     var authData = localStorageService.get('authorizationData'); 
     if (authData) 
     { 
      _authentication.isAuth = true; 
      _authentication.userName = authData.userName; 
     } 

    } 

    authServiceFactory.saveRegistration = _saveRegistration; 
    authServiceFactory.login = _login; 
    authServiceFactory.logOut = _logOut; 
    authServiceFactory.fillAuthData = _fillAuthData; 
    authServiceFactory.authentication = _authentication; 

    return authServiceFactory; 
}]); 

wraz z

'use strict'; 
app.factory('authInterceptorService', ['$q', '$location', 'localStorageService', function ($q, $location, localStorageService) { 

    var authInterceptorServiceFactory = {}; 

    var _request = function (config) { 

     config.headers = config.headers || {}; 

     var authData = localStorageService.get('authorizationData'); 
     if (authData) { 
      config.headers.Authorization = 'Bearer ' + authData.token; 
     } 

     return config; 
    } 

    var _responseError = function (rejection) { 
     if (rejection.status === 401) { 
      $location.path('/login'); 
     } 
     return $q.reject(rejection); 
    } 

    authInterceptorServiceFactory.request = _request; 
    authInterceptorServiceFactory.responseError = _responseError; 

    return authInterceptorServiceFactory; 
}]); 
+0

Dzięki Andrew. To właśnie seria artykułów zapoczątkowała moją drogę i chciałbym ją zrealizować. Mam to wszystko na miejscu, ale gdy próbuję uzyskać HttpContext.Current.User w moim SimpleAuthorizationServerProvider.GrantResourceOwnerCredentials, to jest null i nie mogę uzyskać głównego. Ustawiam atrybut grantu na "hasło", tak jak poleca artykuł, ale nie mogę uzyskać zleceniodawcy. – mmoreno79

+0

czy możesz wysłać kod z klasy 'SecurityHelper'? – Claies

+0

Po wypróbowaniu kilku rzeczy okazuje się, że moje wdrożenie serii artykułów, które pierwotnie sugerował Andrew, naprawdę działało. "Przeszkoda", którą próbowałem przejść, polegała na tym, że otrzymałem główną nazwę użytkownika z HttpContext.Current.GetOwinContext(). Request.User. To zwracało wartość ** null ** w mojej metodzie GetCurrentUser(). Cóż, okazało się, że powrócił ** null **, ponieważ użyłem Skrzypka do skomponowania mojej prośby i przetestowania autoryzacji. Z kaprysu po prostu utworzyłem kontroler testowy w mojej kanciastej aplikacji, aby poprosić o token i mój użytkownik jest teraz wypełniony! – mmoreno79

1

Sprawdź ten artykuł na schodach na umożliwieniu uwierzytelniania systemu Windows w OWIN: http://www.asp.net/aspnet/overview/owin-and-katana/enabling-windows-authentication-in-katana

Z artykułu:

Katana nie przewiduje obecnie OWIN middleware dla uwierzytelniania systemu Windows, ponieważ tego funkcjonalności jest już dostępny na serwerach.

Połączony artykuł obejmuje włączanie uwierzytelniania systemu Windows dla programowania. W przypadku wdrożeń te ustawienia znajdują się w IIS w obszarze Uwierzytelnianie. Użytkownicy zostaną poproszeni o podanie nazwy użytkownika i hasła przez przeglądarkę po ich pierwszym przybyciu na stronę aplikacji.

+0

Dzięki Dawida. Mam już wyłączone uwierzytelnianie anonimowe i włączono uwierzytelnianie systemu Windows w moim projekcie, ale szukałem więcej wskazówek, jak radzić sobie z tokenami na okaziciela między moją aplikacją SPA (angularną) a aplikacją web api. – mmoreno79

Powiązane problemy