WCF能够共享ASP.NET的session,不同的WCF客户端代理类在采用Per Call模式下访问WCF能够访问同一个ASP.NET Session.但是WCF的Session和ASP.NET的Session是不同的。
- WCF的Session代表着服务实例,它是被客户端代理类访问时初始化的。WCF依靠消息通道,安全回话和消息模式等来联系session的。
- 而ASP.NET的session是类似服务端的一种存储数据的模式。它是通过客户端cookie和uri来维护session的
1. 利用ASP.NET的session实现认证,在aspx里记录用户认证信息:
string UserId = HttpContext.Current.User.Identity.Name;
int Timeout = HttpContext.Current.Session.Timeout
2. 如果WCF服务端能够共享Asp.NET的session,必须在WCF配置文件中进行如下设置:
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
3.在服务端新建一个用户类:
public static class UserHelper
{
public const string SessionUserKey = "Session_Current_User";
/// <summary>
/// 取得当前用户信息
/// </summary>
public static UserInfo CurrentUser
{
get
{
if (!HttpContext.Current.User.Identity.IsAuthenticated)
{
HttpContext.Current.Response.Redirect(System.Configuration.ConfigurationManager.AppSettings["LogoutRedirectUrl"]);
return null;
}
string key = SessionUserKey;
object user = null;
if(HttpContext.Current.Session != null)
user = HttpContext.Current.Session[key];
if (user == null)
{
var info = new AdminService().GetUserById(HttpContext.Current.User.Identity.Name); // 获取用户信息
HttpContext.Current.Session[key] = info;
return info;
}
return (UserInfo)user;
}
set { HttpContext.Current.Session[SessionUserKey] = value; }
}
}
4. 在WCF服务端可以利用共享的session来判断权限:
[Serializable]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public partial class AdminService : IAdminService
{
public AdminService()
{
}
public string InsertAdmin(Admin admin)
{
int errorCount = 0;
if (!UserHelper.CurrentUser == null)
{
CustomerFaultException exception = new CustomerFaultException
{
ExceptionCode = "S001",
ExceptionMessage = "没有权限访问,请登录!"
};
throw new FaultException<CustomerFaultException>(exception);
}
AdminSummary adminSummary = adminDal.GetAdminSummary(admin.UserId, out errorCount);
if (adminSummary == null)
return adminDal.InsertAdmin(admin);
else
return "1001";
}
5.在客户端获取sessionId,我们可以通过Cookie获取客户端的sessionId
void InitialInvoke()
{
IHelloService proxy = factory.CreateChannel();
using (new OperationContextScope((IContextChannel)proxy))
{
Console.WriteLine(proxy.Greet("Hello"));
HttpResponseMessageProperty responseProperty = OperationContext.Current.IncomingMessageProperties[HttpResponseMessageProperty.Name]
as HttpResponseMessageProperty;
helper = HttpSessionCookieHelper.Create((string)responseProperty.Headers[HttpResponseHeader.SetCookie]);
}
((IClientChannel)proxy).Close();
}
httpSessionCookieHelper是从cookie中获取sessionId的(CookieName 是“ASP.NET_SessionId”) class HttpSessionCookieHelper
{
const string AspNetSessionIdCookieName = "ASP.NET_SessionId";
string aspNetSessionId = string.Empty;
HttpSessionCookieHelper()
{ }
public static HttpSessionCookieHelper Create(string cookieString)
{
HttpSessionCookieHelper helper = new HttpSessionCookieHelper();
helper.ParseCookieString(cookieString);
return helper;
}
public static HttpSessionCookieHelper CreateFromSessionId(string sessionId)
{
HttpSessionCookieHelper helper = new HttpSessionCookieHelper();
helper.aspNetSessionId = sessionId;
return helper;
}
public void AddSessionIdToRequest(HttpRequestMessageProperty requestProperty)
{
if (string.IsNullOrEmpty(this.aspNetSessionId))
return;
string sessionCookieString = string.Format("{0}={1}", AspNetSessionIdCookieName, this.aspNetSessionId);
string cookieString = (string)requestProperty.Headers[HttpRequestHeader.Cookie];
if (string.IsNullOrEmpty(cookieString))
{
cookieString = sessionCookieString;
}
else
{
cookieString = string.Format("{0}; {1}", cookieString, sessionCookieString);
}
requestProperty.Headers[HttpRequestHeader.Cookie] = cookieString;
}
void ParseCookieString(string cookieString)
{
if (string.IsNullOrEmpty(cookieString))
return;
string[] cookies = cookieString.Split(';');
for (int i = 0; i < cookies.Length; i++)
{
string[] cookieNameValues = cookies[i].Split('=');
if (cookieNameValues[0] == AspNetSessionIdCookieName)
{
this.aspNetSessionId = cookieNameValues[1];
return;
}
}
}
public string AspNetSessionId
{
get
{
return this.aspNetSessionId;
}
}
}
这样我们可以在第一次调用的回复中获取sessionId
void Invoke2()
{
IHelloService proxy = factory.CreateChannel();
using (new OperationContextScope((IContextChannel)proxy))
{
HttpRequestMessageProperty requestProperty = new HttpRequestMessageProperty();
helper.AddSessionIdToRequest(requestProperty);
OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = requestProperty;
Console.WriteLine(proxy.Greet("Howdy"));
}
((IClientChannel)proxy).Close();
if (Interlocked.Increment(ref completedCount) == 2)
{
waitHandle.Set();
}
}
注:第5点可以参照:
http://blogs.msdn.com/b/wenlong/archive/2010/02/21/using-asp-net-sessions-from-wcf.aspx