前面也提到了,前段时间在做Online Judge系统,在正式上线前有几个比较老的版本,其中第一个版本使用ACL来控制权限以确保安全(但是这个版本完全建立在IIS上,所以这样做是没效果的),遇到了一些问题,至于问题是什么以后有机会再说,那么解决这些问题曾想到一个办法,更改文件的所有者。
在搜索引擎里搜索“C# 修改文件所有者”都会搜索到很多类似《c# 更改文件访问权限 所有者(适用于win7以下版本) 》,但是就没出现过《c# 更改文件访问权限 所有者(适用于各个Windows版本) 》。为什么要特意强调适用于win7以下版本,是因为
FileInfo fi = new FileInfo(@"d:\囧.txt");
FileSecurity fs = fi.GetAccessControl();
NTAccount currentAccount = (NTAccount)fs.GetOwner(typeof(NTAccount));
Console.WriteLine("先前的所有者为 " + currentAccount.Value);
NTAccount admins = new NTAccount("administrators");//注意 这里是administrators 而不是administrator 他表示管理员组而非一个单个的帐号
fs.SetOwner(admins);
fi.SetAccessControl(fs);
Console.WriteLine("当前的所有者为 " + fi.GetAccessControl().GetOwner(typeof(NTAccount)).Value);
这样做会在Windows 7以及更高版本上go die(不允许将安全标识符作为此对象的所有者),高版本Windows需要用Win32API,如果手工去操作会复杂很多。偶然在*上找到一篇文章说到了一个解决方案,由于年代久远不可考(其实是懒当时没记忘了)所以就不贴原文了。
爆栈网上的答主给的方法是使用一个外部库,这个库看名字就知道是干什么的,用起来也特别方便:
贴段老代码(应该是这么用的,这个版本还能跑起来):
File.Copy(outfileName, tempfileName);
var everyone = new SecurityIdentifier(WellKnownSidType.WorldSid, null);
var domain = new FileInfo(outfileName).GetAccessControl().GetOwner(typeof(NTAccount)).Value.Split('\\')[0];
var user = new FileInfo(outfileName).GetAccessControl().GetOwner(typeof(NTAccount)).Value.Split('\\')[1];
var ediFileOwner = new NTAccount(domain, user);
var fileSecurity = File.GetAccessControl(outfileName);
File.SetAccessControl(outfileName, fileSecurity);
File.Delete(outfileName);
File.Move(tempfileName, outfileName);
var aosSID = (SecurityIdentifier)ediFileOwner.Translate(typeof(SecurityIdentifier));
File.SetAccessControl(outfileName, fileSecurity);
using (new Impersonator(/*UserName*/, domain, /*UserPassword*/))
{
fileSecurity = File.GetAccessControl(outfileName);
fileSecurity.SetOwner(ediFileOwner);
File.SetAccessControl(outfileName, fileSecurity);
}
在注释处填写要更改为的所有者的账户名和密码。虽然看起来很复杂的样子,其实过程非常简单:创建源文件的副本,获得它的信息,干掉源文件,改名副本然后调用Impersonator来设置所有者。
使用前,这个锅是杨某的:
执行后,这个锅就甩了: