昨天在万网尝试发布公司的网站,是请一家设计公司做的,asp.net。发布之后,其他功能都正常,但就是后台管理登陆之后进不去:
提示 System.UnauthorizedAccessException:拒绝访问
但是有一点很奇怪,公司的另一个网站,也在万网托管,服务器环境一模一样,后台管理也是用的同一套程序,却可以正常进入后台而不报错。
于是花了将近一天的时间把两个网站的代码比较了个遍,愣是没有发现什么实质性的不同。
因为自己也不了解asp.net,查了半天都查不出来,网上百度的,都一些常见的原因,解决的办法无非是修改 web.config文件或者是修改 IIS设置,但这是万网的托管服务,IIS什么的都没有问题,网上那些方法都不起作用,看来是另有原因。
无奈之下找了万网客服,最终,对方的工程师找到了问题的原因,是因为这个网站的登陆功能中用到了wmi(这个wmi我也是第一次听说),而万网的服务器设置是不允许使用wmi的,因此会提示拒绝访问某个资源。
下面就来说说这个问题的详细情况以及解决的办法:
一开始,客服大概说了下是wmi的问题,说是我的网站程序尝试去获取网卡信息,所以被拒绝。那么我第一步就要去找到程序中使用到wmi的地方:
通过百度,我发现C#中用到wmi的地方都会引用System.management , 但是很可惜,找遍了所有 .aspx.cs 文件,也没找到这个引用,难道这个网站程序确实没有使用wmi?
很无奈得把找不到wmi操作的事情告诉了客服:
不过,客服这次给出了更详细的解答:
这次,我总算有点开窍了,在 aspx.cs文件中找不到System.management引用,并不代表没有wmi操作,这种操作完全可以放在 dll文件中进行!下面是客服给我的dll截图:
这里就很清楚了,这个 GetLocalMac() 方法试图获取服务器的网卡Mac地址。那网站程序为什么要获取服务器的网卡Mac地址呢?想来想去无非就是要记录登录日志吧,于是查看了网站的数据库,果然,日志中确实有Mac地址字段:
接下来,就该找出程序中哪里调用了wmi操作了。
第一,很自然地就能想到,在Login 这个操作中应该会进行日志记录,也就是包含了获取网卡的操作;
第二,根据保存的信息来看,也确实是登录操作时报错;
if (Administrator.ManageUser.Login(UserName.Text, System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(UserPassword.Text, "MD5")))
因为上文那个dll文件的名字是Administrator.dll,所以看到这里的 Administrator.ManagUser.Login()...,也就很自然得想到可以通过反编译查看dll里面Login()方法的详细内容:
可以看到,Login方法的最后一步,确实进行了日志记录,那么,获取网卡的操作很有可能就在它的第一个参数中:Log.category.Login.ToString(),于是打开Administrator下面的Log,果然发现了GetLocalMac()方法!正是这个方法试图获取万网服务器的Mac地址被拒绝,因此报错。
好了,问题的原因总算是弄清楚了,可是,下面就遇到了实质性的问题,那怎样修改程序使它不记录网卡Mac地址呢?
这个wmi操作是在dll里面的,反正dll我是没法改,那怎么办呢?
忽然想起了另外一个能正常进入后台的网站,它的程序基本和这个网站是同一套,也是相同的dll,那么可以看看它是怎么修改的呢?
下面来比较一下:
1. 问题网站:
if (Administrator.ManageUser.Login(UserName.Text, System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(UserPassword.Text, "MD5")))
2. 正常网站:
if (Login(UserName.Text, System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(UserPassword.Text, "MD5")))
public static bool Login(string UserName, string UserPassword)
{
bool result = Administrator.ManageUser.ValidateManageUser(UserName, UserPassword);
if (result)
{
Administrator.ManageUser user = new Administrator.ManageUser(UserName);
user.LastVisitTime = DateTime.Now;
user.LoginTimes += 1;
user.Update();
HttpCookie Cookie = new HttpCookie("ManagerUser");
Cookie.Name = "ManagerUser";
Cookie.Value = HttpContext.Current.Server.UrlEncode(UserName);
Cookie.Expires = DateTime.Now.Add(new TimeSpan(3, 0, 0));
HttpContext.Current.Response.Cookies.Add(Cookie);
}
return result;
}
这个方法看着很眼熟啊!下面再来看看dll中的Login方法是怎么写的吧:
public static bool Login(string UserName, string UserPassword)
{
bool flag = ValidateManageUser(UserName, UserPassword);
if (flag)
{
ManageUser user = new ManageUser(UserName);
user.LastVisitTime = DateTime.Now;
user.LoginTimes++;
user.Update();
HttpCookie cookie = new HttpCookie("ManagerUser");
cookie.Name = "ManagerUser";
cookie.Value = HttpContext.Current.Server.UrlEncode(UserName);
cookie.Expires = DateTime.Now.Add(new TimeSpan(3, 0, 0));
HttpContext.Current.Response.Cookies.Add(cookie);
Log.CreateEventLog(Log.category.Login.ToString(), "管理员登录", "", 0, user.ManagerId, user.AdminUserName);
}
return flag;
}
于是也照此方法重写Login(),测试,成功!
经此一役,算是第一次实质性地接触了dll 的内容。