2015-05-07 19 views
5

Ho un progetto in VB.NET che utilizza l'appartenenza di asp.net per gestire l'autenticazione dell'utente. Ora voglio creare un'app per Android per questo progetto, quindi ho deciso di imparare WCF e ho avuto una media sui servizi web WCF. Ora il problema che sto affrontando è che quando il login utente in app Android quello che succede:Mantenere lo stato tra le chiamate al servizio web WCF da Android

  1. Richiesta va alle credenziali webapplication e utente vengono autenticati.
  2. Dopodiché, quando l'utente tenta di inviare dati o tenta di visualizzare i dati, la richiesta ritorna all'applicazione Web, ma ora l'applicazione Web deve autenticare l'utente in base alle credenziali che ha fornito nella prima richiesta di accesso dall'appartenenza autenticazione.

Ora il problema sto affrontando come autenticare l'utente in appartenenza asp.net per ogni richiesta WCF in modalità chiamata Servizio per sessione da java (Android).

+1

Non so perché questa domanda è in diminuzione, ogni cosa in esso è chiara ed è una buona domanda per learing. Penso che questo forum stia perdendo il suo valore e stia diventando sempre più interessato ai problemi di sintassi e ignorando i problemi di programmazione. – killer

+1

Controlla questo link: http://dotnetspeak.com/2012/01/securing-wcf-with-forms-authentication – UserControl

+0

@Shoaib AspnetCompatibilityMode è impostato su true inoltre ho aggiunto il servizio al progetto asp.net. Anche i clienti per l'app sono utenti registrati – killer

risposta

1

Ci sono diversi modi per fare ciò che penso tu stia chiedendo, ho pensato (e scritto) alcune diverse potenziali soluzioni, tuttavia, quello che sto condividendo qui è qualcosa che penso possa "incastrare" -in "a soluzioni esistenti utilizzando il provider di appartenenze/ruoli ASP.NET. Spero di averti dato abbastanza informazioni per fare ciò che devi fare, ma puoi sempre commentare e fare più domande se qualcosa non è ancora chiaro.

Nel tuo problema descrivi l'utilizzo di un'applicazione Web ASP.NET contenente un servizio WCF per i client esistenti, ma stai cercando di espandere l'utilizzo delle richieste Android (java)? Dato che il provider di appartenenze ASP.NET utilizza un sacco di interscambi SOAP "dietro le quinte" (per l'autenticazione, l'autorizzazione e la crittografia) che sembrano essere integrati nei framework di riferimento del servizio, sarebbe un compito abbastanza grande scrivere un'implementazione java. ..

Quindi, ti ho scritto un esempio di qualcosa che si integrerà allo stesso provider "backend", ma ti permetterà anche di inviare richieste SOAP da qualsiasi client senza bisogno del riferimento del servizio (l'ho provato usando SoapUI per esempio) ... Ho scritto la mia soluzione in C# (dato che sono stati scritti gli esempi di WCF), tuttavia è possibile utilizzare facilmente un code-converter to switch it to VB.NET. Inoltre, non ti ho fornito il metodo per crittografare e decrittografare le password, dovrai fare una ricerca per te stesso.

È necessario implementare un nuovo file .svc nella soluzione esistente e creare di conseguenza le nuove voci di web.config (presumo che tu sappia già come creare un endpoint di base e un endpoint di servizio).

Avrete anche bisogno di duplicare le chiamate di metodo (o invece, creare una nuova classe con il contenuto metodo e farvi riferimento da ovunque ci si sta implementando i metodi ServiceContract) e rimuovere il "[PrincipalPermission (SecurityAction" attributi, e aggiungere i metodi di esempio riportato di seguito nel nuovo servizio di esempio (utilizzando metodi da MembershipAndRoleProvider WCF Sample di Microsoft) -

// Allows all Users to call the Add method 
    [PrincipalPermission(SecurityAction.Demand, Role = "Users")] 
    public double Add(double n1, double n2) 
    { 
     double result = n1 + n2; 
     return result; 
    } 

diventerebbero:.

// Allows all Users to call the Add method   
    public double Add(double n1, double n2, string username, string token) 
    { 
     string isAuthorized = IsAuthorized(username, "Users", token) 
     if (isAuthorized.Contains("Success") 
      double result = n1 + n2; 
      return result; 
     else 
      throw new Exception("Authorization Exception: " + isAuthorized); 
    } 

Ecco la mia applicazione (s), integrato nel Microsoft WCF Sample MembershipAndRoleProvider (download dal here):

IsolatedAuthService.SVC

<%@ServiceHost Language="C#" Debug="true" Service="Microsoft.ServiceModel.Samples.IsolatedAuthService" CodeBehind="IsolatedAuthService.cs" %> 

IIsolatedAuthService.cs

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Runtime.Serialization; 
using System.ServiceModel; 
using System.Text; 

namespace Microsoft.ServiceModel.Samples 
{ 
    // Define a service contract. 
    [ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples")] 
    public interface IIsolatedAuthService 
    { 
     [OperationContract] 
     string IsAuthorized(string username, string roleName, string token); 
     [OperationContract] 
     string AuthenticateUser(string username, string encryptedPassword); 
    } 
} 

IsolatedAuthService.cs

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Runtime.Serialization; 
using System.ServiceModel; 
using System.Text; 
using System.Web; 
using System.Web.Hosting; 
using System.Web.Security; 
using System.Web.Configuration; 
using System.Configuration; 
using System.IO; 
using System.Security.Permissions; 
using System.Security.Principal; 
using System.ServiceModel.Activation; 
using System.Threading; 

namespace Microsoft.ServiceModel.Samples 
{ 
    public class IsolatedAuthService : IIsolatedAuthService 
    { 
     public string IsAuthorized(string username, string roleName, string token) 
     { 
      MembershipUser user = Membership.GetAllUsers()[username]; 

      Configuration config = ConfigurationManager.OpenExeConfiguration(HostingEnvironment.MapPath("~") + "\\web.config");   

      SessionStateSection sessionStateConfig = (SessionStateSection)config.SectionGroups.Get("system.web").Sections.Get("sessionState"); 

      InMemoryInstances instance = InMemoryInstances.Instance; 

      // Check for session state timeout (could use a constant here instead if you don't want to rely on the config). 
      if (user.LastLoginDate.AddMinutes(sessionStateConfig.Timeout.TotalMinutes) < DateTime.Now) 
      { 
       // Remove token from the singleton in this instance, effectively a logout.     
       instance.removeTokenUserPair(username); 
       return "User Unauthorized - login has expired!"; 
      } 

      if (!instance.checkTokenUserPair(username, token)) 
       return "User Unauthorized - not a valid token!"; 

      // Check for role membership. 
      if (!Roles.GetUsersInRole(roleName).Contains(user.UserName)) 
       return "User Unauthorized - Does not belong in that role!"; 

      return "Success - User is Authorized!"; 
     } 

     public string AuthenticateUser(string username, string encryptedPassword) 
     { 
      if (Membership.ValidateUser(username, Decrypt(encryptedPassword))) 
      { 
       // Not sure if this is actually needed, but reading some documentation I think it's a safe bet to do here anyway. 
       Membership.GetAllUsers()[username].LastLoginDate = DateTime.Now; 

       // Send back a token! 
       Guid token = Guid.NewGuid(); 

       // Store a token for this username. 
       InMemoryInstances instance = InMemoryInstances.Instance; 
       instance.removeTokenUserPair(username); //Because we don't implement a "Logout" method. 
       instance.addTokenUserPair(username, token.ToString()); 

       return token.ToString(); 
      } 

      return "Error - User was not able to be validated!"; 
     } 
    } 
} 

InMemoryInstances.cs

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace Microsoft.ServiceModel.Samples 
{ 
    public class InMemoryInstances 
    { 
     private static volatile InMemoryInstances instance; 
     private static object syncRoot = new Object(); 

     private Dictionary<string, string> usersAndTokens = null; 

     private InMemoryInstances() 
     { 
      usersAndTokens = new Dictionary<string, string>(); 
     } 

     public static InMemoryInstances Instance 
     { 
      get 
      { 
       if (instance == null) 
       { 
        lock (syncRoot)     
        { 
         if (instance == null) 
          instance = new InMemoryInstances(); 
        } 
       } 

       return instance; 
      } 
     } 

     public void addTokenUserPair(string username, string token) 
     { 
      usersAndTokens.Add(username, token); 
     } 

     public bool checkTokenUserPair(string username, string token) 
     { 
      if (usersAndTokens.ContainsKey(username)) { 
       string value = usersAndTokens[username]; 
       if (value.Equals(token)) 
        return true; 
      } 

      return false; 
     } 

     public void removeTokenUserPair(string username) 
     { 
      usersAndTokens.Remove(username); 
     } 
    } 
} 

Bare a mente, questa soluzione non funzionerà se si esegue il bilanciamento del carico del servizio WCF su più server (a causa della classe di istanze in memoria), è possibile modificare la soluzione per utilizzare una tabella di database anziché le istanze in memoria se questo è un requisito per te.

Problemi correlati