2015-05-07 19 views
5

Mam projekt w VB.NET, który korzysta z członkostwa asp.net do zarządzania uwierzytelniania użytkownika. Teraz chcę zbudować aplikację na Androida dla tego projektu, więc postanowiłem nauczyć się WCF i mam średni chwyt na serwisach WCF. Teraz problem jestem stoi to, że podczas logowania użytkownika do aplikacji na Androida następujące konsekwencje:Zachowanie stanu między wywołaniami usług WCF z Androidem

  1. Zapytanie trafia do poświadczenia webapplication i użytkownika są uwierzytelnione.
  2. Po tym, gdy użytkownik spróbuje przesłać jakiekolwiek dane lub spróbować wyświetlić dane, należy ponownie przejść do aplikacji internetowej, ale teraz aplikacja internetowa powinna uwierzytelnić użytkownika na podstawie poświadczeń podanych w pierwszym żądaniu logowania z członkostwa poświadczenie.

Teraz problem, w jaki sposób uwierzytelniać użytkownika w członkostwie asp.net dla każdego żądania WCF w trybie wywołania Service Per-Session z java (Android).

+1

Nie wiem, dlaczego ta kwestia została odrzucona, wszystko w niej jest jasne i jest dobrym pytaniem do nauki. Myślę, że to forum traci swoją wartość i coraz bardziej zajmuje się kwestiami składni i ignoruje problemy z programowaniem. – killer

+1

Sprawdź ten link: http://dotnetspeak.com/2012/01/securing-wcf-withformform-authentication – UserControl

+0

@Shoaib AspnetCompatibilityMode jest ustawiony na true również dodałem usługę do projektu asp.net. Również klienci aplikacji są zarejestrowani: – killer

Odpowiedz

1

Jest kilka sposobów na zrobienie tego, o czym myślę, że pytasz, myślałem o (i napisałem) o kilku różnych potencjalnych rozwiązaniach, jednak ten, który tu prezentuję, jest czymś, -w "do istniejących rozwiązań przy użyciu członkostwa ASP/NET/Roles Provider. Mam nadzieję, że dałem ci wystarczająco dużo informacji, aby zrobić to, co musisz zrobić, ale zawsze możesz skomentować i zadać więcej pytań, jeśli coś jest nadal niejasne.

W swoim problemie opisujesz za pomocą aplikacji sieci Web ASP.NET zawierającej usługę WCF dla istniejących klientów, ale chcesz rozszerzyć do korzystania z żądań systemu Android (java)? Biorąc pod uwagę, że dostawca członkostwa ASP.NET używa wielu "nawiasów" do wymiany SOAP (w celu uwierzytelnienia, autoryzacji i szyfrowania), które wydają się być wbudowane w struktury referencyjne usług, byłoby dość dużym zadaniem napisanie implementacji java. ..

Tak, napisałem Ci przykład czegoś, co połączy się z tym samym dostawcą "zaplecza", ale pozwoli ci również wysyłać żądania SOAP od dowolnego klienta bez potrzeby odwoływania się do usługi (testowałem to za pomocą SoapUI na przykład) ... Napisałem moje rozwiązanie w języku C# (ponieważ to, w jaki sposób zostały napisane próbki WCF), jednak można całkiem łatwo użyć code-converter to switch it to VB.NET. Nie udostępniam ci również metody szyfrowania i odszyfrowywania haseł, musisz sam to zbadać.

Będziesz musiał zaimplementować nowy plik .svc do istniejącego rozwiązania i odpowiednio utworzyć nowe wpisy web.config (zakładam, że już wiesz, jak utworzyć element basicHttpBinding i punkt końcowy usługi).

Trzeba także powielać połączeń metodzie (lub zamiast tworzyć nową klasę z treścią metody i odwoływać od gdziekolwiek jesteś wdrażaniu metod ServiceContract) i usunąć „[PrincipalPermission (SecurityAction” atrybuty i dodać metody poniższy przykład do nowej usługi przykład (przy użyciu metody z Microsoftu MembershipAndRoleProvider WCF Sample) -

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

staną.

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

Oto moja implementacja (s), zintegrowany z Microsoft WCF Sample MembershipAndRoleProvider (do pobrania z 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); 
     } 
    } 
} 

Należy pamiętać, że to rozwiązanie nie będzie działało, jeśli równoważymy obciążenie usługi WCF na wielu serwerach (ze względu na klasę instancji w pamięci), można zmienić rozwiązanie, aby używać tabeli bazy danych zamiast wystąpienia w pamięci, jeśli jest to wymagane.