维护来自android

时间:2015-05-07 10:45:15

标签: c# asp.net wcf wcf-data-services

我在VB.NET中有一个项目,它使用asp.net成员资格来管理用户身份验证。现在我想为这个项目构建android应用程序,所以我决定学习WCF并且我已经获得了WCF webservices的平均保留。现在我面临的问题是当用户登录到Android应用程序后发生以下事情:

  1. 请求转到Web应用程序,用户凭据经过身份验证。
  2. 之后,当用户尝试提交任何数据或尝试查看数据时,请求再次转到Web应用程序,但现在Web应用程序应根据他在第一次成员登录请求中提供的凭据对用户进行身份验证认证
  3. 现在我面临的问题是如何在java(Android)的每会话服务呼叫模式中为每个WCF请求验证asp.net成员资格中的用户。

1 个答案:

答案 0 :(得分:1)

有几种方法可以做我认为你要求的东西,我已经想到(并且写了)一些不同的潜在解决方案,但是,我在这里分享的是我认为会“插槽”的东西。在“使用ASP.NET Membership / Roles Provider的现有解决方案中”。希望我已经给了你足够的信息来做你需要做的事情,但如果还有什么不清楚的话,你可以随时发表评论并提出更多问题。

在您的问题中,您描述了为现有客户端使用包含WCF服务的ASP.NET Web应用程序,但您是否希望扩展为使用Android(Java)请求?鉴于ASP.NET成员资格提供程序使用了许多似乎内置于服务引用框架中的“幕后”SOAP交换(用于身份验证,授权和加密),编写Java实现是一项相当大的任务。 ..

所以,我写了一个可以集成到同一个“后端”提供程序的示例,但也允许您从任何客户端发送SOAP请求而无需服务引用(我使用{{3进行了测试)例如)...我在C#中编写了我的解决方案(因为它是WCF示例的编写方式),但是,您可以很容易地使用SoapUI。我还没有为您提供加密和解密密码的方法,您必须自己研究这一点。

您需要在现有解决方案中实现新的.svc文件,并相应地创建新的web.config条目(我假设您已知道如何创建basicHttpBinding和服务端点)。

您还需要复制方法调用(或者,使用方法内容创建一个新类,并从实现ServiceContract方法的任何位置引用它)并删除“ [PrincipalPermission(SecurityAction < / em>“属性,并将以下示例方法添加到新服务中。 例如(使用Microsoft的code-converter to switch it to VB.NET中的方法) -

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

会变成:

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

这是我的实施,已集成到MembershipAndRoleProvider WCF Sample(从Microsoft WCF Sample MembershipAndRoleProvider下载):

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

请记住,如果您跨多个服务器对WCF服务进行负载均衡(由于内存中的实例类),此解决方案将无效,您可以将解决方案更改为使用数据库表而不是in -memory实例,如果这是你的要求。