2012-07-03 16 views
13

Come posso utilizzare il gestore ruoli in un servizio WCF?Come posso utilizzare il gestore ruoli in un servizio WCF?

Nella mia applicazione .NET, posso limitare una classe o un metodo con il tag [Authorize(Roles=)]. Come posso abilitare questo per il mio servizio WCF?

ho attualmente la seguente serie vincolante per ciascun endpoint:

<webHttpBinding> 
    <binding name="TransportSecurity" maxReceivedMessageSize="5242880"> 
     <security mode="Transport"> 
     <transport clientCredentialType="None"/> 
     </security> 
    </binding> 
    </webHttpBinding> 

Dato che voglio avere il registro utente e di ricevere un cookie con il preside, ho bisogno di cambiare questo ad un altro tipo di clientCredentialType ?

Edit 1:

Questo è utilizzando REST, SOAP non. È anche importante notare che è importante che funzioni con i dispositivi mobili (Android, iPhone) e che possa utilizzare i cookie per mantenere una sessione. Finora, sono stato in grado di ottenere questo lavoro, utilizzando il seguente codice/config: File

Config:

<roleManager enabled="true" defaultProvider="ActiveDirectoryRoleProvider" cacheRolesInCookie="true" cookieName="RoleCookie" cookiePath="/" cookieTimeout="30" cookieRequireSSL="false" cookieSlidingExpiration="true" createPersistentCookie="false" cookieProtection="All"> 
     <providers> 
     <clear /> 
     <add name="ActiveDirectoryRoleProvider" connectionStringName="ADServices" connectionUsername="" connectionPassword="" attributeMapUsername="sAMAccountName" type="" /> 
     </providers> 
    </roleManager> 

    <membership defaultProvider="MembershipADProvider"> 
     <providers> 
     <add name="MembershipADProvider" type="System.Web.Security.ActiveDirectoryMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" applicationName="" connectionStringName="ADServices" connectionUsername="" connectionPassword="" attributeMapUsername="sAMAccountName" /> 
     </providers> 
    </membership> 

<bindings> 
    <webHttpBinding> <!-- webHttpBinding is for REST --> 
    <binding name="TransportSecurity" maxReceivedMessageSize="5242880"> 
     <security mode="Transport"> 
     </security> 
    </binding> 
    </webHttpBinding> 
</bindings> 

<behaviors> 
    <endpointBehaviors> 
    <behavior name="web"> 
     <webHttp /> 
    </behavior> 
    </endpointBehaviors> 
    <serviceBehaviors> 
    <behavior name="ServiceBehaviour"> 
     <serviceMetadata httpGetEnabled="false" httpsGetEnabled="true" /> 
     <serviceDebug httpHelpPageEnabled="true" includeExceptionDetailInFaults="true" /> 
     <serviceAuthorization principalPermissionMode="UseAspNetRoles" roleProviderName="ActiveDirectoryRoleProvider" /> 
     <serviceCredentials> 
     <userNameAuthentication userNamePasswordValidationMode="MembershipProvider" membershipProviderName="MembershipADProvider" /> 
     </serviceCredentials> 
    </behavior> 
    </serviceBehaviors> 
</behaviors> 

Codice

public void SignIn2(string userName, bool createPersistentCookie) 
    { 
     if (String.IsNullOrEmpty(userName)) throw new ArgumentException("Value cannot be null or empty.", "userName"); 

     // put the attributes in a string for userdata 
     string userData = ""; 

     // create the ticket 
     FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(1, 
               userName, 
               DateTime.Now, 
               DateTime.Now.AddMinutes(240), 
               createPersistentCookie, 
               userData); 

     // Now encrypt the ticket. 
     string encryptedTicket = FormsAuthentication.Encrypt(authTicket); 

     // Create a cookie and add the encrypted ticket to the cookie as data. 
     HttpCookie authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket); 

     // add the cookie 
     HttpContext.Current.Response.Cookies.Add(authCookie); 
    } 

Ora utilizzando il Principal Autorizzazione, ottengo un SecurityException (so che il ruolo è valido sul server)

[PrincipalPermission(SecurityAction.Demand, Role = Constants.RoleUser)] 
    public Message TestRoles() 
    { 
     var context = NetworkHelper.GetWebOperationContext(); 

     return context.CreateTextResponse("You have successfully activated the endpoint."); 
    } 

Mi manca un passaggio cruciale qui?

risposta

9

ho scritto a blog post su come utilizzando l'autenticazione ASP.NET con WCF; l'essenza di esso è che si desidera utilizzare il seguente legame:

<basicHttpBinding> 
    <binding> 
     <security mode="TransportWithMessageCredential"> 
     <message clientCredentialType="UserName"/> 
     </security> 
    </binding> 
    </basicHttpBinding> 

È necessario applicare anche il seguente serviceBehavior

<behavior> 
     <!-- no need for http get; 
      but https get exposes endpoint over SSL/TLS--> 
     <serviceMetadata httpGetEnabled="false" httpsGetEnabled="true"/> 
     <!-- the authorization and credentials elements tie 
     this behavior (defined as the default behavior) to 
     the ASP.NET membership framework--> 
     <serviceAuthorization 
      principalPermissionMode="UseAspNetRoles" 
      roleProviderName="AspNetRoleProvider" /> 
     <serviceCredentials> 
     <userNameAuthentication 
      userNamePasswordValidationMode="MembershipProvider" 
      membershipProviderName="AspNetMembershipProvider" /> 
     </serviceCredentials> 
    </behavior> 

Un punto importante da notare è che è necessario utilizzare SSL se siete andando a proteggere WCF con un nome e una password, ecco perché è specificata la sicurezza del trasporto.

Una volta fatto, dovresti essere in grado di utilizzare l'attributo PrincipalPermission per proteggere i tuoi metodi di servizio.

+0

Vedo, ho appena visto che l'attributo 'Autorizza' è MVC-centrico. Dovrò usare il 'PrincipalPermission', presumo che funzioni in modo molto simile? – Cody

+0

+1: ottima risposta! Apparentemente Microsoft ha seguito questo argomento con un articolo su MSDN sull'utilizzo dei provider di ruolo con WCF: http://msdn.microsoft.com/en-us/library/aa702542.aspx – reSPAWNed

+0

Ciao. Per favore, dai un'occhiata a questa domanda : https: //stackoverflow.com/questions/45770217/my-customauthorizationpolicy-evaluate-method-never-fires –

2

penso che qualcosa di simile a questo fornirà quello che stai cercando:

// Only members of the SpecialClients group can call this method. 
[PrincipalPermission(SecurityAction.Demand, Role = "SpecialClients")] 
public void DoSomething() 
{ 
} 

È possibile trovare un buon articolo sulle diverse opzioni per la configurazione del servizio qui: MSDN Article. Si consiglia di aggiornare la configurazione con qualcosa di simile:

<security mode="TransportWithMessageCredential" > 
    <transport clientCredentialType="Windows" /> 
</security> 
2

Due anni fa ho eseguito il blogging su una integrazione wcf con l'autenticazione di moduli e gli attributi di autorizzazione principale.Credo che troverete questo utile:

http://netpl.blogspot.com/2010/04/aspnet-forms-authentication-sharing-for.html

+0

Non sono sicuro che questo aiuti nella mia situazione. – Cody

+0

Ciò che ti manca rispetto al mio approccio: 1) non hai impostato threadprincipal su context.user 2) non hai la compatibilità asp.net 3) dovresti anche remand Authenticated = true in PrincipalPermission oltre a ruoli specifici –

+0

Ho tutte queste cose impostate e non funziona. – Cody

1

check-out questa domanda Passing FormsAuthentication cookie to a WCF service. Il punto principale è che il cookie di autenticazione non può essere né inviato né ricevuto, a causa del dominio cookie/impostazioni asp/chiave di crittografia dell'autorizzazione. Vi consiglio di scaricare quel valore del cookie per scopi di debug Request.Cookies [". ASPXAUTH"].

3

Ho avuto il problema simile con il principale, tanto tempo fa. Non ricordo i dettagli, ma prova questo, dal mio vecchio progetto:

i. È necessario aggiungere le classi helper 2:


using System.Web; 
using System.IdentityModel.Claims; 
using System.IdentityModel.Policy; 

namespace TicketingCore 
{ 
    public class HttpContextPrincipalPolicy : IAuthorizationPolicy 
    { 
     public bool Evaluate(EvaluationContext evaluationContext, ref object state) 
     { 
      HttpContext context = HttpContext.Current; 

      if (context != null) 
      { 
       evaluationContext.Properties["Principal"] = context.User; 
      } 

      return true; 
     } 

     public System.IdentityModel.Claims.ClaimSet Issuer 
     { 
      get { return ClaimSet.System; } 
     } 

     public string Id 
     { 
      get { return "TicketingCore HttpContextPrincipalPolicy"; } 
     } 
    } 
} 


using System; 
using System.Collections.Generic; 
using System.IdentityModel.Claims; 
using System.IdentityModel.Policy; 
using System.Text; 
using System.Web; 
using System.Security.Principal; 

namespace TicketingCore 
{ 
    // syncs ServiceSecurityContext.PrimaryIdentity in WCF with whatever is set 
    // by the HTTP pipeline on Context.User.Identity (optional) 
    public class HttpContextIdentityPolicy : IAuthorizationPolicy 
    { 
     public bool Evaluate(EvaluationContext evaluationContext, ref object state) 
     { 
      HttpContext context = HttpContext.Current; 

      if (context != null) 
      { 
       // set the identity (for PrimaryIdentity) 
       evaluationContext.Properties["Identities"] = 
        new List<IIdentity>() { context.User.Identity }; 

       // add a claim set containing the client name 
       Claim name = Claim.CreateNameClaim(context.User.Identity.Name); 
       ClaimSet set = new DefaultClaimSet(name); 
       evaluationContext.AddClaimSet(this, set); 
      } 

      return true; 
     } 

     public System.IdentityModel.Claims.ClaimSet Issuer 
     { 
      get { return ClaimSet.System; } 
     } 

     public string Id 
     { 
      get { return "TicketingCore HttpContextIdentityPolicy"; } 
     } 
    } 
} 

II. Modificare il WebConfig per aggiungere questi 2 politica, ecco la mia configurazione (formato: aggiungi PolicyType = "namespace.class, montaggio")

<serviceBehaviors> 
    <behavior name="ServiceBehavior"> 
     <serviceCredentials> 
     <userNameAuthentication userNamePasswordValidationMode="MembershipProvider" membershipProviderName="SQLMembershipProvider"/> 
     </serviceCredentials> 
     <serviceAuthorization principalPermissionMode="Custom"> 
     <authorizationPolicies> 
      <add policyType="TicketingCore.HttpContextIdentityPolicy, TicketingCore"/> 
      <add policyType="TicketingCore.HttpContextPrincipalPolicy, TicketingCore"/> 
     </authorizationPolicies> 
     </serviceAuthorization> 
     <serviceMetadata httpGetEnabled="true"/> 
     <serviceDebug includeExceptionDetailInFaults="false"/> 
    </behavior> 
    </serviceBehaviors> 

iii. Assicurati che il cookie e il ruolo funzionino correttamente

Nota: non ricordo la fonte della soluzione, potrebbe essere necessario il nome della classe su google per scoprirlo, spero che ti sarà utile, buona fortuna!

+0

Questo è l'esempio più completo su Internet e sembra essere il modo più corretto per eseguire l'autorizzazione utilizzando l'autenticazione basata su form in un servizio WCF. Un problema correlato è come eseguire l'autenticazione all'interno della chiamata di servizio stessa e restituire un errore 401 invece di affidarsi a un web.config IIS per negare agli utenti anonimi l'accesso alla sottodirectory del servizio. – Monstieur

+0

Esempio di progetto ovunque? – Rhyous

Problemi correlati