积极答复者
将用户登录验证等单独做个项目,发布到某个虚拟目录下,其他项目的页面需要登录时,都去调用该登录界面,并返回登录前界面;登录一次后,其他项目就不需要调用了,怎样实现呢?

问题
答案
-
您好,下面提供的是同一个域名内的方法。
首先需要保证cookie能在不同的项目中访问,需要配置machinekey。效果类似:
<machineKey
validationKey="21F090935F6E49C2C797F69BBAAD8402ABD2EE0B667A8B44EA7DD4374267A75D7
AD972A119482D15A4127461DB1DC347C1A63AE5F1CCFAACFF1B72A7F0A281B"
decryptionKey="ABAA84D7EC4BB56D75D217CECFFB9628809BDB8BF91CFCD64568A145BE59719F"
validation="SHA1"
decryption="AES"
/>
具体参考:http://msdn.microsoft.com/zh-cn/library/ms998288.aspx
http://msdn.microsoft.com/zh-cn/library/w8h3skw9.aspx
然后,使用一致的身份验证:
在Global中类似:
void Application_AuthenticateRequest(Object sender, EventArgs e)
{
string cookieName = FormsAuthentication.FormsCookieName;
HttpCookie authCookie = Context.Request.Cookies[cookieName];
if (null == authCookie)
{
// There is no authentication cookie.
return;
}
FormsAuthenticationTicket authTicket = null;
try
{
authTicket = FormsAuthentication.Decrypt(authCookie.Value);
}
catch (Exception ex)
{
// Log exception details (omitted for simplicity)
throw ex;
// return;
}
if (null == authTicket)
{
// Cookie failed to decrypt.
return;
}
// When the ticket was created, the UserData property was assigned a
// pipe delimited string of role names.
string[] roles = authTicket.UserData.Split(new char[] { '|' });
// Create an Identity object
FormsIdentity id = new FormsIdentity(authTicket);
// This principal will flow throughout the request.
System.Security.Principal.GenericPrincipal principal = new System.Security.Principal.GenericPrincipal(id,roles);
// Attach the new principal object to the current HttpContext object
Context.User = principal;
}- 已标记为答案 ahking 2011年3月4日 0:00
全部回复
-
您好,下面提供的是同一个域名内的方法。
首先需要保证cookie能在不同的项目中访问,需要配置machinekey。效果类似:
<machineKey
validationKey="21F090935F6E49C2C797F69BBAAD8402ABD2EE0B667A8B44EA7DD4374267A75D7
AD972A119482D15A4127461DB1DC347C1A63AE5F1CCFAACFF1B72A7F0A281B"
decryptionKey="ABAA84D7EC4BB56D75D217CECFFB9628809BDB8BF91CFCD64568A145BE59719F"
validation="SHA1"
decryption="AES"
/>
具体参考:http://msdn.microsoft.com/zh-cn/library/ms998288.aspx
http://msdn.microsoft.com/zh-cn/library/w8h3skw9.aspx
然后,使用一致的身份验证:
在Global中类似:
void Application_AuthenticateRequest(Object sender, EventArgs e)
{
string cookieName = FormsAuthentication.FormsCookieName;
HttpCookie authCookie = Context.Request.Cookies[cookieName];
if (null == authCookie)
{
// There is no authentication cookie.
return;
}
FormsAuthenticationTicket authTicket = null;
try
{
authTicket = FormsAuthentication.Decrypt(authCookie.Value);
}
catch (Exception ex)
{
// Log exception details (omitted for simplicity)
throw ex;
// return;
}
if (null == authTicket)
{
// Cookie failed to decrypt.
return;
}
// When the ticket was created, the UserData property was assigned a
// pipe delimited string of role names.
string[] roles = authTicket.UserData.Split(new char[] { '|' });
// Create an Identity object
FormsIdentity id = new FormsIdentity(authTicket);
// This principal will flow throughout the request.
System.Security.Principal.GenericPrincipal principal = new System.Security.Principal.GenericPrincipal(id,roles);
// Attach the new principal object to the current HttpContext object
Context.User = principal;
}- 已标记为答案 ahking 2011年3月4日 0:00
-
现在做的项目都是发布到内部网, 没有域名,地址都是类似http://10.0.0.12/account的,这样的用上面的方法可以跨地址么?
比如http://10.0.0.17/myapp调用http://10.0.0.12/account下的登录进行验证
-
现在做的项目都是发布到内部网, 没有域名,地址都是类似http://10.0.0.12/account 的,这样的用上面的方法可以跨地址么?
比如http://10.0.0.17/myapp 调用http://10.0.0.12/account 下的登录进行验证
这种情况我没试过,我看到跨域的读取都是将cookie改为字符串,然后再次验证一下。或者您可以尝试统一设置cookie的domain。 -
有些项目不要求先登录,只有操作特定的页面才要求登录,设置Global恐怕不适用吧
Global的Application_AuthenticateRequest是统一验证的入口,如果不在这,那么将要在每个页面上去设置,那将很烦琐。对于无需验证的,我上面的代码中也判断了,不用担心。像这一段:if (null == authCookie)
{
// There is no authentication cookie.
return;
}
我在web.config中的<location path="" >中设定需要登录的界面也可以吧?我参考http://msdn.microsoft.com/zh-cn/library/eb0zx8fc.aspx对machineKey进行了配置,有一次出现了错误:
验证视图状态 MAC 失败。如果此应用程序由网络场或群集承载,请确保 <machineKey> 配置指定了相同的 validationKey 和验证算法。不能在群集中使用 AutoGenerate。
说明: 执行当前 Web 请求期间,出现未处理的异常。请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息。
虽然只出现了一次,但是我仍然很担心将来部署到生产环境会出现不稳定的情况 -
machineKey里的validationKey和decryptionKey要再计算。这里有详细的解释,我上面已贴出,http://msdn.microsoft.com/zh-cn/library/ms998288.aspx 或参考<asp.net3.5揭秘>中关于membership的章节。
我按照这篇文章http://msdn.microsoft.com/zh-cn/library/eb0zx8fc.aspx,直接把machineKey里的validationKey和decryptionKey值复制下来了,这样不行么? -
machineKey里的validationKey和decryptionKey要再计算。这里有详细的解释,我上面已贴出,http://msdn.microsoft.com/zh-cn/library/ms998288.aspx 或参考<asp.net3.5揭秘>中关于membership的章节。
我按照这篇文章http://msdn.microsoft.com/zh-cn/library/eb0zx8fc.aspx ,直接把machineKey里的validationKey和decryptionKey值复制下来了,这样不行么?
按理是可以。可您用公开的key,别人就能解密,留下一个安全隐患。最好生成machineKey。 -
另外,我搜到别人也遇到过类似的问题,不知以下解决方法是否可行
如果你使用了一些比较复杂的控件(asp.net控件方式的HTML编辑器并且包含了一篇复杂文章就经常如此),看看你的页面上的ViewState是不是很大。如果很大,可以使用我下面的代码放到你的页面中:
- C# code
-
using System; using System.IO; using System.Web.UI; public class XVPage : Page { static private DirectoryInfo _Dir; private DirectoryInfo Dir { get { if (_Dir == null) { _Dir = new DirectoryInfo(Server.MapPath("~/App_Data/")); if (!_Dir.Exists) _Dir.Create(); _Dir = new DirectoryInfo(Path.Combine(_Dir.FullName, "ViewState")); if (!_Dir.Exists) _Dir.Create(); } return _Dir; } } protected override object LoadPageStateFromPersistenceMedium() { PageStatePersister ps = this.PageStatePersister; ps.Load(); if (ps.ControlState != null) ps.ControlState = 反序列化对象((string)ps.ControlState); if (ps.ViewState != null) ps.ViewState = 反序列化对象((string)ps.ViewState); return new Pair(ps.ControlState, ps.ViewState); } protected override void SavePageStateToPersistenceMedium(object state) { PageStatePersister ps = this.PageStatePersister; if (state is Pair) { Pair pair = (Pair)state; ps.ControlState = pair.First; ps.ViewState = pair.Second; } else { ps.ViewState = state; } if (ps.ControlState != null) ps.ControlState = 序列化对象(ps.ControlState); if (ps.ViewState != null) ps.ViewState = 序列化对象(ps.ViewState); ps.Save(); } private object 反序列化对象(string stateID) { string stateStr = (string)Cache[stateID]; string file = Path.Combine(Dir.FullName, stateID); if (stateStr == null) stateStr = File.ReadAllText(file); else Cache.Remove(stateID); return new ObjectStateFormatter().Deserialize(stateStr); } private string 序列化对象(object obj) { string value = new ObjectStateFormatter().Serialize(obj); string stateID = (DateTime.Now.Ticks + (long)value.GetHashCode()).ToString(); //产生离散的id号码 File.WriteAllText(Path.Combine(Dir.FullName, stateID), value); Cache.Insert(stateID, value); return stateID; } protected override void OnUnload(EventArgs e) { base.OnUnload(e); DateTime dt = DateTime.Now.AddMinutes(-20); foreach (FileInfo fl in Dir.GetFiles()) if (fl.LastAccessTime < dt) try { fl.Delete(); } catch { } } }
你可以把它作为你的页面的父页面。 -
哈,您在一个问题里,索要的也太多了吧。
关于工具,上面我贴的连接里有c#的例子,您是否有看呢?
您最后贴的这段代码是关于降低web form的viewstate的,跟我们讨论的身份验证完全两码事!八杆子打不着的。
呵呵,问题都是关联的,上面那段代码讲的就是由于viewstate太大而导致验证视图状态 MAC 失败的
好,不错!实战中如果安全要求不高,也可以尝试将EnableViewStateMac设为false。
另我们明确的设置了machinekey。我不明白这加密解密跟viewstate的大小有什么关系?
您现在刚好有环境,能否往viewstate中放一个很多行记录的datatable,然后测试一下,期待您的分享!