我在VB.NET中有一个项目,它使用asp.net成员资格来管理用户身份验证。现在我想为这个项目构建android应用程序,所以我决定学习WCF并且我已经获得了WCF webservices的平均保留。现在我面临的问题是当用户登录到Android应用程序后发生以下事情:
现在我面临的问题是如何在java(Android)的每会话服务呼叫模式中为每个WCF请求验证asp.net成员资格中的用户。
答案 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实例,如果这是你的要求。