2014-11-06 14 views
14

Potrei complicare eccessivamente le cose, ma abbiamo un ASP.NET interno MVC5 SPA con AngularJS che utilizza l'autenticazione di Windows. Questa applicazione ha un database back-end SQL che ha una tabella di utenti, contenente i loro nomi account e i rispettivi ruoli nell'applicazione. Effettueremo chiamate a un'altra applicazione API Web che dispone anche dell'autenticazione di Windows abilitata.ASP.NET MVC5/AngularJS/App API Web utilizzando l'autenticazione di Windows e OWIN

Ho provato a fare ricerche su come gestire l'autorizzazione utilizzando OWIN ma non sono riuscito a trovare esempi specifici relativi a OWIN e all'autenticazione di Windows. Tutto ciò che appare utilizza l'autenticazione dei moduli con un nome utente e una password.

Come posso utilizzare OWIN e Windows Auth per la mia app? Ecco un esempio della mia classe 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: Ops, ho dimenticato di includere ulteriori informazioni su ciò che vorremmo realizzare. Se possibile, vorremmo utilizzare i ticket di autenticazione al portatore in modo da non dover cercare l'utente e i relativi ruoli ogni volta che effettuiamo una chiamata a un metodo API web.

UPDATE 2: Come richiesto da Andrew, di seguito è la versione TLDR della mia classe _securityHelper, in particolare il metodo GetCurrentUser(). Noterete che sto cercando di chiamare:

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

Questa restituisce sempre nulla per l'utente.

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

risposta

5

Questa serie di articoli sarebbe un buon punto di partenza: http://bitoftech.net/2014/06/01/token-based-authentication-asp-net-web-api-2-owin-asp-net-identity/

di nota, sarebbe il seguente codice, che memorizza in sostanza il token portatore nella memoria locale e lo collega alle intestazioni. Ovviamente c'è molto di più, inclusi i moduli e l'attuale sistema di autenticazione del server, ma questo dovrebbe darti un buon inizio.componente

server:

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

    } 
} 

e il seguente codice lato client:

'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; 
}]); 

insieme

'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

Grazie Andrew. Questa è la serie di articoli che mi ha spinto a intraprendere questa strada e mi piacerebbe implementarla. Ho tutto a posto, ma quando provo a ottenere HttpContext.Current.User nel mio SimpleAuthorizationServerProvider.GrantResourceOwnerCredentials, è nullo e non riesco a ottenere il principale. Ho impostato il grant_type su "password" come raccomandato dall'articolo ma non riesco a ottenere il principal. – mmoreno79

+0

puoi pubblicare il codice dalla tua classe 'SecurityHelper'? – Claies

+0

Dopo aver provato alcune cose, si scopre che la mia implementazione della serie di articoli che Andrew aveva suggerito in origine stava funzionando. L'ostacolo che stavo cercando di superare era ottenere l'utente principale da HttpContext.Current.GetOwinContext(). Request.User. Ciò stava restituendo ** null ** nel mio metodo GetCurrentUser(). Bene, risulta che stava restituendo ** null ** perché stavo usando Fiddler per comporre la mia richiesta e testare l'autenticazione. Per un capriccio, ho semplicemente creato un controller di test nella mia app angolare per richiedere un token e il mio utente è ora popolato! – mmoreno79

1

leggi questo articolo per i passaggi su come abilitare l'autenticazione di Windows in OWIN: http://www.asp.net/aspnet/overview/owin-and-katana/enabling-windows-authentication-in-katana

Dall'articolo:

Katana non fornisce attualmente OWIN middleware per l'autenticazione di Windows, perché questa funzionalità è già disponibile nei server.

L'articolo collegato copre l'abilitazione dell'autenticazione di Windows per lo sviluppo. Per le distribuzioni, queste impostazioni sono in IIS in Autenticazione. Agli utenti verrà richiesto il nome utente e la password dal browser quando arrivano per la prima volta sulla pagina dell'applicazione.

+0

Grazie David. Ho già un'autenticazione anonima disabilitata e l'autenticazione di Windows abilitata nel mio progetto, ma cercavo più indicazioni su come gestire i token bearer tra la mia SPA (app angolare) e l'app web api. – mmoreno79

Problemi correlati