6

Ich versuche ein AngularJs-Web zu erstellen, das Login und Passwort an ein ASP.NET WebApi-Backend sendet und diesen Benutzer mit Thinktecture anmeldet.AngularJs ASP.NET WebApi Authentifizierung mit Thinktecture

Ich habe Thinktecture gut mit anderen Projekt, ASP.NET MVC, mit WS-Federation. Jetzt versuche ich etwas ähnliches zu tun, aber einige Komponenten zu ändern und ich kann es nicht funktionieren lassen.

Wie kann ich von ASP.NET WebApi den Benutzernamen und das Kennwort an Thinktecture senden und validieren lassen?

using System.Collections.Generic; 
using System.IdentityModel.Services; 
using System.Web.Http; 
using WebApi_AngularJs.Model; 

namespace WebApi_AngularJs.Controllers 
{ 
    public class AuthorizationController : ApiController 
    {  
     // POST: api/Authorization 
     public LoginResponse Post([FromBody]Login data) 
     { 
      //HOW TO SEND data.user and data.password to ThinkTecture and get 
      //response if user valid or not?? 
      var response = new LoginResponse { access_token = "token", data = "data"}; 
      return response; 
     } 

    } 
} 

Vielen Dank!

Antwort

5

Schließlich, nach viel zu lesen Ich habe dies:

In AngularJS:

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

var serviceBase = 'http://localhost:64346/'; 
var authServiceFactory = {}; 

var _authData = localStorageService.get('authorizationData'); 

var _authentication = { 
    isAuth: _authData != null? true : false, 
    userName: _authData != null ? _authData.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 + 'api/authorization', 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() { 

    $http.delete(serviceBase + 'api/authorization').success(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; 
}]); 

In WebAPI:

using System.Collections.Generic; 
using System.Configuration; 
using System.IdentityModel.Protocols.WSTrust; 
using System.IdentityModel.Services; 
using System.IdentityModel.Tokens; 
using System.IO; 
using System.Linq; 
using System.Net; 
using System.Security.Claims; 
using System.ServiceModel; 
using System.ServiceModel.Description; 
using System.ServiceModel.Security; 
using System.Web.Http; 
using System.Xml; 
using Thinktecture.IdentityModel.Constants; 
using Thinktecture.IdentityModel.WSTrust; 
using WebApi_AngularJs.Model; 

namespace WebApi_AngularJs.Controllers 
{ 
    public class AuthorizationController : ApiController 
    { 
     // GET: api/Authorization 
     public IEnumerable<string> Get() 
     { 
      return new string[] { "value1", "value2" }; 
     } 

     // GET: api/Authorization/5 
     [Authorize] 
     public string Get(int id) 
     { 
      return "value"; 
     } 

    // POST: api/Authorization 
    public LoginResponse Post([FromBody]Login data) 
    { 
     var credentials = new ClientCredentials(); 
     credentials.UserName.UserName = data.UserName; 
     credentials.UserName.Password = data.Password; 

     ServicePointManager.ServerCertificateValidationCallback = (obj, certificate, chain, errors) => true; 

     var claims = GetClaimsFromIdentityServer(data.UserName, data.Password); 

     var response = new LoginResponse(); 
     if (claims != null) 
     { 
      //All set so now create a SessionSecurityToken 
      var token = new SessionSecurityToken(claims) 
      { 
       IsReferenceMode = true //this is 
       //important.this is how you say create 
       //the token in reference mode meaning 
       //your session cookie will contain only a 
       //referenceid(which is very small) and 
       //all claims will be stored on the server 
      }; 
      FederatedAuthentication.WSFederationAuthenticationModule. 
      SetPrincipalAndWriteSessionToken(token, true); 

      response = new LoginResponse { access_token = token.Id , data = "data"}; 
     } 

     return response; 
    } 

    // PUT: api/Authorization/5 
    public void Put(int id, [FromBody]string value) 
    { 
    } 

    // DELETE: api/Authorization/ 
    public void Delete() 
    { 
     //clear local cookie 
     FederatedAuthentication.SessionAuthenticationModule.SignOut(); 
     FederatedAuthentication.SessionAuthenticationModule.DeleteSessionTokenCookie(); 
     FederatedAuthentication.WSFederationAuthenticationModule.SignOut(false); 
    } 

    private ClaimsPrincipal GetClaimsFromIdentityServer(string username, string password) 
    { 
     const string WS_TRUST_END_POINT = "https://srv:4443/issue/wstrust/mixed/username"; 
     var factory = new System.ServiceModel.Security.WSTrustChannelFactory 
     (new UserNameWSTrustBinding(SecurityMode.TransportWithMessageCredential), 
            string.Format(WS_TRUST_END_POINT)); 
     factory.TrustVersion = TrustVersion.WSTrust13; 
     factory.Credentials.UserName.UserName = username; 
     factory.Credentials.UserName.Password = password; 

     var rst = new System.IdentityModel.Protocols.WSTrust.RequestSecurityToken 
     { 
      RequestType = RequestTypes.Issue, 
      KeyType = KeyTypes.Bearer, 
      TokenType = TokenTypes.Saml2TokenProfile11, 
      AppliesTo = new EndpointReference 
      ("urn:webapisecurity") 
     }; 
     var st = factory.CreateChannel().Issue(rst); 
     var token = st as GenericXmlSecurityToken; 
     var handlers = FederatedAuthentication.FederationConfiguration. 
     IdentityConfiguration.SecurityTokenHandlers; 
     var token = handlers.ReadToken(new XmlTextReader 
     (new StringReader(token.TokenXml.OuterXml))) as Saml2SecurityToken; 
     var identity = handlers.ValidateToken(token).First(); 
     var principal = new ClaimsPrincipal(identity); 
     return principal; 
    } 
} 
} 

In Web.Config:

<?xml version="1.0" encoding="utf-8"?> 
<!-- 
    For more information on how to configure your ASP.NET application, please visit 
    http://go.microsoft.com/fwlink/?LinkId=301879 
    --> 
<configuration> 
    <configSections> 
    <section name="system.identityModel" type="System.IdentityModel.Configuration.SystemIdentityModelSection, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" /> 
    <section name="system.identityModel.services" type="System.IdentityModel.Services.Configuration.SystemIdentityModelServicesSection, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" /> 
    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 --> 
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" /> 
    </configSections> 
    <appSettings> 
    <add key="webpages:Version" value="3.0.0.0" /> 
    <add key="webpages:Enabled" value="false" /> 
    <add key="ClientValidationEnabled" value="true" /> 
    <add key="UnobtrusiveJavaScriptEnabled" value="true" /> 
    <add key="ida:FederationMetadataLocation" value="https://srv:4443/FederationMetadata/2007-06/FederationMetadata.xml" /> 
    <add key="ida:Realm" value="urn:webapisecurity" /> 
    <add key="ida:AudienceUri" value="urn:webapisecurity" /> 
    <add key="AppName" value="Web API Security Sample" /> 
    </appSettings> 
    <system.web> 
    <compilation debug="true" targetFramework="4.5" /> 
    <httpRuntime targetFramework="4.5" /> 
    </system.web> 
    <system.webServer> 
    <handlers> 
     <remove name="ExtensionlessUrlHandler-Integrated-4.0" /> 
     <remove name="OPTIONSVerbHandler" /> 
     <remove name="TRACEVerbHandler" /> 
     <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" /> 
    </handlers> 
    <modules> 
     <add name="WSFederationAuthenticationModule" type="System.IdentityModel.Services.WSFederationAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="managedHandler" /> 
     <add name="SessionAuthenticationModule" type="System.IdentityModel.Services.SessionAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="managedHandler" /> 
    </modules> 
    <validation validateIntegratedModeConfiguration="false" /> 
    </system.webServer> 
    <system.identityModel> 
    <identityConfiguration> 
     <audienceUris> 
     <add value="urn:webapisecurity" /> 
     </audienceUris> 
     <claimsAuthorizationManager type="Thinktecture.IdentityServer.Ofi.AuthorizationManager, Thinktecture.IdentityServer.Ofi, Version=1.0.0.0, Culture=neutral" /> 
     <claimsAuthenticationManager type="Thinktecture.IdentityServer.Ofi.AuthenticationManager, Thinktecture.IdentityServer.Ofi, Version=1.0.0.0, Culture=neutral" /> 
     <certificateValidation certificateValidationMode="None" /> 
     <issuerNameRegistry type="System.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> 
     <trustedIssuers> 
      <add thumbprint="489116B0FCF14DF66D47AE272C3B9FD867D0E050" /> 
     </trustedIssuers> 
     </issuerNameRegistry> 
    </identityConfiguration> 
    </system.identityModel> 
    <system.identityModel.services> 
    <federationConfiguration> 
     <cookieHandler requireSsl="false" /> 
     <wsFederation passiveRedirectEnabled="true" issuer="https://srv:4443/issue/wsfed" realm="urn:webapisecurity" reply="http://localhost:64346/" requireHttps="false" /> 
    </federationConfiguration> 
    </system.identityModel.services> 
    <runtime> 
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> 
     <dependentAssembly> 
     <assemblyIdentity name="System.Web.Optimization" publicKeyToken="31bf3856ad364e35" /> 
     <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="1.1.0.0" /> 
     </dependentAssembly> 
     <dependentAssembly> 
     <assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" /> 
     <bindingRedirect oldVersion="0.0.0.0-1.5.2.14234" newVersion="1.5.2.14234" /> 
     </dependentAssembly> 
     <dependentAssembly> 
     <assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" /> 
     <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" /> 
     </dependentAssembly> 
     <dependentAssembly> 
     <assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" /> 
     <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" /> 
     </dependentAssembly> 
     <dependentAssembly> 
     <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" /> 
     <bindingRedirect oldVersion="0.0.0.0-5.1.0.0" newVersion="5.1.0.0" /> 
     </dependentAssembly> 
     <dependentAssembly> 
     <assemblyIdentity name="System.Web.Http" publicKeyToken="31bf3856ad364e35" culture="neutral" /> 
     <bindingRedirect oldVersion="0.0.0.0-5.1.0.0" newVersion="5.1.0.0" /> 
     </dependentAssembly> 
     <dependentAssembly> 
     <assemblyIdentity name="System.Net.Http.Formatting" publicKeyToken="31bf3856ad364e35" culture="neutral" /> 
     <bindingRedirect oldVersion="0.0.0.0-5.1.0.0" newVersion="5.1.0.0" /> 
     </dependentAssembly> 
    </assemblyBinding> 
    </runtime> 
    <entityFramework> 
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" /> 
    <providers> 
     <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" /> 
    </providers> 
    </entityFramework> 
</configuration> 

Damit kann ich FedAuth kochen sehen Dh im Browser eingestellt und es macht auch die Validierung in WebApi.

+0

Ja, das funktioniert auch, die Lösung, die ich gab, ist jedoch besser geeignet, wenn Sie SSO wollen. –

+0

Vielen Dank für die Veröffentlichung Ihrer Lösung. Das hat mir geholfen zu verteilen !! Es ist auch schön, sich über einen Proxy anzumelden, anstatt zu Idsrv umzuleiten. Nochmals vielen Dank. – StefanHa

+0

Froh, Ihnen zu helfen! – cdiazal

6

Es gibt ein paar Dinge, die Sie tun müssen. Erstellen Sie einen OAuth-Client, der Token-Anforderungen stellt, und verwenden Sie diese, um Zugriffstoken vom Identitätsserver zu erhalten, mit denen Sie auf Ihre Web-API-Endpunkte zugreifen können. Dazu muss Ihr OAuth-Client den impliziten Fluss aktiviert haben. Anschließend melden Sie sich beim Identity Server an, normalerweise über ein Popup-Fenster, in dem sich Ihr OAuth-Client anmelden kann. Sie müssen Ihre OAuth-Client-Details in der Abfragezeichenfolge der Login-Anfrage an Idsrv, eine OAuth-Client-Konfiguration, übergeben wäre das, was Sie für den OAuth-Client in Ihrem Panel Admin Idsrv definiert, würde parametrieren Sie, dass es auf die oauth2/authorzie uRL anhängen:

getIdpOauthEndpointUrl: function() { 
       return "https://192.168.1.9/issue/oauth2/authorize"; 
}, 
getOAuthConfig: function() { 
       return { 
        client_id: "Your Oauth CLient ID that you specifie din Identity Server", 
        scope: "The scope of your RP", 
        response_type: "token", 
        redirect_uri: "https://..YourAngularAppUrl/AuthCallback.html" 
       }; 
} 

Sie dann das Login-Fenster öffnen:

var url = authService.getIdpOauthEndpointUrl() + "?" + $.param(authService.getOAuthConfig()); 
        window.open(url, "Login", "height=500,width=350"); 

In Ihrem OAuth-Client inIdsrv müssen Sie eine Weiterleitungs-URL angeben, in unserem Fall:

https://YourAngularAppUrl/AuthCallback.html 

Dies ist, was Sie in die Anmeldungsanfrage zum Identitätsserver zusammen mit Ihnen OAuth-Client-Details übergeben. Die Seite AuthCallback.html extrahiert lediglich das von idsrv an diese Seite in einer Abfragezeichenfolge zurückgegebene Zugriffstoken und übergibt es an Ihre eckige App. Wie Sie dies tun, hängt davon ab, aber dieses Zugriffstoken muss in Ihre Kopfzeilen $http eingegeben werden .

Das Zugriffstoken kann in Ihrer AuthCallback.html Seite wie folgt extrahiert werden:

<script src="/Scripts/jquery-2.0.3.js"></script> 
<script src="/Scripts/jquery.ba-bbq.min.js"></script> 

<script type="text/javascript"> 
    var params = $.deparam.fragment(location.hash.substring(1)); 

    window.opener.oAuthCallback(params); 
    window.close(); 
</script> 

die OAuthCallback Funktion in meiner Schale Seite definiert ist, ist meine index.html und verantwortlich für die Token-Passing es in gegeben hat meine eckige App und setze es in die $http Header.

function oAuthCallback(OAUTHTOKEN) { 
    angular.element(window.document).scope().setHttpAuthHeaderAndAuthenticate(OAUTHTOKEN); 
} 

Die setHttpAuthHeaderAndAuthenticate() Funktion auf meine $rootScope definiert ist, und es setzt das Token in den $http authorizaiton Header:

$http.defaults.headers.common.Authorization = 'Bearer ' + OAUTHTOKEN["access_token"];

einen Blick auf this post von Christian Weyer hat es tut genau das, was wir re tun, aber es ist eine Knockout/Web-API-App, das gleiche Konzept immer noch.

Der nächste Schritt ist, Ihre Web-API zu sagen, dass sie das Zugriffstoken von idsrv akzeptiert, das ist einfach;

public static void Configure(HttpConfiguration config) 
     { 
      var authConfig = new AuthenticationConfiguration(); 

      authConfig.AddJsonWebToken(
    YourIdsrvSiteId, YourRpsScope/Relam,YourRpsSymmetricSigningKey 
); 

      config.MessageHandlers.Add(new AuthenticationHandler(authNConfig)); 
     } 

Sie könnten auch einen ClaimsAuthenticationManager und ClaimsAuthorizationManager hier definieren, damit Sie Ansprüche zu transformieren und Grant/Deny Zugang sto die Web-api Ressourcen. Auch das ist alles in Christian Weyers Post. Hoffe das hilft.

+0

Ich werde auch so versuchen, viel zu lernen! Vielen Dank! – cdiazal

Verwandte Themen