내 .NET 2.0 응용 프로그램에서는 디렉터리에 파일을 만들고 쓸 수있는 충분한 권한이 있는지 확인해야합니다. 이 목적을 위해 파일을 만들고 단일 바이트를 쓰고 나중에 사용 권한이 있는지 테스트하기 위해 자체를 삭제하려고 시도하는 다음 함수가 있습니다.
나는 최선의 방법을 확인하는 것은 실제로 시도하고 예외를 잡는 것이었다. 나는 예외적 인 캐치 (catch)에 대해 특히 행복하지는 않다. 그렇기 때문에 이보다 더 좋은 방법이 있을까?
private const string TEMP_FILE = "\\tempFile.tmp";
/// <summary>
/// Checks the ability to create and write to a file in the supplied directory.
/// </summary>
/// <param name="directory">String representing the directory path to check.</param>
/// <returns>True if successful; otherwise false.</returns>
private static bool CheckDirectoryAccess(string directory)
{
bool success = false;
string fullPath = directory + TEMP_FILE;
if (Directory.Exists(directory))
{
try
{
using (FileStream fs = new FileStream(fullPath, FileMode.CreateNew,
FileAccess.Write))
{
fs.WriteByte(0xff);
}
if (File.Exists(fullPath))
{
File.Delete(fullPath);
success = true;
}
}
catch (Exception)
{
success = false;
}
}
답변리차드과제이슨일종의 올바른 방향입니다. 그러나 당신이해야 할 일은유효 사용 권한 계산하기코드를 실행하는 사용자 ID 위의 예에서는 그룹 구성원 자격을 올바르게 설명하지 않습니다.
나는 꽤 확신한다.키스 브라운이 일을하는 몇 가지 코드가있다.위키 버전(현재 오프라인 상태 임).NET 개발자를위한 Windows 보안 가이드. 이것은 또한 그의프로그래밍 Windows 보안책.
효과적인 사용 권한을 계산하는 것은 희소하고 코드가 파일을 만들려고 시도하는 것이 아니며 발생하는 보안 예외를 잡는 것은 아마도 최소한의 저항의 길일 것입니다.
Directory.GetAcessControl(path)
당신이 요구하는 것을합니다.
public static bool HasWritePermissionOnDir(string path)
{
var writeAllow = false;
var writeDeny = false;
var accessControlList = Directory.GetAccessControl(path);
if (accessControlList == null)
return false;
var accessRules = accessControlList.GetAccessRules(true, true,
typeof(System.Security.Principal.SecurityIdentifier));
if (accessRules ==null)
return false;
foreach (FileSystemAccessRule rule in accessRules)
{
if ((FileSystemRights.Write & rule.FileSystemRights) != FileSystemRights.Write)
continue;
if (rule.AccessControlType == AccessControlType.Allow)
writeAllow = true;
else if (rule.AccessControlType == AccessControlType.Deny)
writeDeny = true;
}
return writeAllow && !writeDeny;
}
(FileSystemRights.Write & rights) == FileSystemRights.Write
"Flags"btw라고 불리는 것을 사용하고 있습니다. 만약 당신이 정말로 무엇을 읽어야하는지 모르겠다면 :)
Deny
우선하다Allow
. 로컬 규칙은 상속 된 규칙보다 우선합니다. 나는 여러 가지 해결책을 보았지만 (여기에 몇 가지 답변을 포함), 아무도 규칙이 있는지 여부를 고려하지 않았다.계승 된아닙니다. 따라서 규칙 상속 (클래스에 깔끔하게 래핑 됨)을 고려한 다음 접근 방식을 제안합니다.
public class CurrentUserSecurity
{
WindowsIdentity _currentUser;
WindowsPrincipal _currentPrincipal;
public CurrentUserSecurity()
{
_currentUser = WindowsIdentity.GetCurrent();
_currentPrincipal = new WindowsPrincipal(WindowsIdentity.GetCurrent());
}
public bool HasAccess(DirectoryInfo directory, FileSystemRights right)
{
// Get the collection of authorization rules that apply to the directory.
AuthorizationRuleCollection acl = directory.GetAccessControl()
.GetAccessRules(true, true, typeof(SecurityIdentifier));
return HasFileOrDirectoryAccess(right, acl);
}
public bool HasAccess(FileInfo file, FileSystemRights right)
{
// Get the collection of authorization rules that apply to the file.
AuthorizationRuleCollection acl = file.GetAccessControl()
.GetAccessRules(true, true, typeof(SecurityIdentifier));
return HasFileOrDirectoryAccess(right, acl);
}
private bool HasFileOrDirectoryAccess(FileSystemRights right,
AuthorizationRuleCollection acl)
{
bool allow = false;
bool inheritedAllow = false;
bool inheritedDeny = false;
for (int i = 0; i < acl.Count; i++) {
var currentRule = (FileSystemAccessRule)acl[i];
// If the current rule applies to the current user.
if (_currentUser.User.Equals(currentRule.IdentityReference) ||
_currentPrincipal.IsInRole(
(SecurityIdentifier)currentRule.IdentityReference)) {
if (currentRule.AccessControlType.Equals(AccessControlType.Deny)) {
if ((currentRule.FileSystemRights & right) == right) {
if (currentRule.IsInherited) {
inheritedDeny = true;
} else { // Non inherited "deny" takes overall precedence.
return false;
}
}
} else if (currentRule.AccessControlType
.Equals(AccessControlType.Allow)) {
if ((currentRule.FileSystemRights & right) == right) {
if (currentRule.IsInherited) {
inheritedAllow = true;
} else {
allow = true;
}
}
}
}
}
if (allow) { // Non inherited "allow" takes precedence over inherited rules.
return true;
}
return inheritedAllow && !inheritedDeny;
}
}
그러나 필자는 항상 파일 액세스 권한을 쿼리 할 수있는 권한이 없으므로 원격 컴퓨터에서이 기능이 작동하지 않는다는 경험을했습니다. 이 경우 해결책은 시도하는 것입니다. "실제"파일로 작업하기 전에 액세스 권한을 알아야하는 경우 임시 파일을 만들려고해도됩니다.
이 질문에 대한 Kev의 대답은 실제로 코드를 제공하지 않으며 액세스 권한이없는 다른 리소스를 가리키고 있습니다. 그래서 여기에 함수에 대한 나의 최선의 시도가있다. 그것은 실제로보고있는 권한이 "쓰기"권한이고 현재 사용자가 해당 그룹에 속해 있는지 확인합니다.
그것은 네트워크 경로 또는 기타와 관련하여 완전하지 않을 수도 있지만 쓰기 목적으로 "Program Files"아래에있는 로컬 구성 파일을 확인하는 것만으로도 충분합니다.
using System.Security.Principal;
using System.Security.AccessControl;
private static bool HasWritePermission(string FilePath)
{
try
{
FileSystemSecurity security;
if (File.Exists(FilePath))
{
security = File.GetAccessControl(FilePath);
}
else
{
security = Directory.GetAccessControl(Path.GetDirectoryName(FilePath));
}
var rules = security.GetAccessRules(true, true, typeof(NTAccount));
var currentuser = new WindowsPrincipal(WindowsIdentity.GetCurrent());
bool result = false;
foreach (FileSystemAccessRule rule in rules)
{
if (0 == (rule.FileSystemRights &
(FileSystemRights.WriteData | FileSystemRights.Write)))
{
continue;
}
if (rule.IdentityReference.Value.StartsWith("S-1-"))
{
var sid = new SecurityIdentifier(rule.IdentityReference.Value);
if (!currentuser.IsInRole(sid))
{
continue;
}
}
else
{
if (!currentuser.IsInRole(rule.IdentityReference.Value))
{
continue;
}
}
if (rule.AccessControlType == AccessControlType.Deny)
return false;
if (rule.AccessControlType == AccessControlType.Allow)
result = true;
}
return result;
}
catch
{
return false;
}
}
BUILTIN\Administrators
. 그리고 내 지역 방송국 관리자이기 때문에 실수로 반환했습니다.true
. - Ilia Barahovski
IMO, 평소와 같은 디렉토리로 작업해야하지만, 사용하기 전에 권한을 확인하는 대신 UnauthorizedAccessException을 처리하고 적절하게 대응할 수있는 올바른 방법을 제공하십시오. 이 방법은 오류가 발생하기 쉽고 훨씬 쉽습니다.
방금 만든 C # 코드 조각으로 작업 해보십시오.
using System;
using System.IO;
using System.Security.AccessControl;
using System.Security.Principal;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string directory = @"C:\downloads";
DirectoryInfo di = new DirectoryInfo(directory);
DirectorySecurity ds = di.GetAccessControl();
foreach (AccessRule rule in ds.GetAccessRules(true, true, typeof(NTAccount)))
{
Console.WriteLine("Identity = {0}; Access = {1}",
rule.IdentityReference.Value, rule.AccessControlType);
}
}
}
}
과여기에참조 할 수도 있습니다. 내 코드는 디렉터리에 쓰기를 시도하기 전에 사용 권한을 확인하는 방법에 대한 아이디어를 줄 수 있습니다.
typeof
이 경우 객체의 유형을 반환합니다.NTAccount
.docs.microsoft.com/en-us/dotnet/csharp/language-reference/…에 대한 호출GetAccessRules()
호출 할 때 계정 유형이 필요합니다.msdn.microsoft.com/en-us/library/… - Jason EvansNTAccount
? 항상 사용하다NTAccount? - KiquenetNTAccount
Windows PC의 사용자 계정을 나타냅니다. 위의 코드에서이 계정이 필요한 이유입니다. - Jason Evans
이 링크에 따르면 :http://www.authorcode.com/how-to-check-file-permission-to-write-in-c/
기존의 클래스 SecurityManager를 사용하는 것이 더 쉽습니다.
string FileLocation = @"C:\test.txt";
FileIOPermission writePermission = new FileIOPermission(FileIOPermissionAccess.Write, FileLocation);
if (SecurityManager.IsGranted(writePermission))
{
// you have permission
}
else
{
// permission is required!
}
하지만 이제는 더 이상 사용하지 않는 것 같지만 대신 PermissionSet을 사용하는 것이 좋습니다.
[Obsolete("IsGranted is obsolete and will be removed in a future release of the .NET Framework. Please use the PermissionSet property of either AppDomain or Assembly instead.")]
private static void GrantAccess(string file)
{
bool exists = System.IO.Directory.Exists(file);
if (!exists)
{
DirectoryInfo di = System.IO.Directory.CreateDirectory(file);
Console.WriteLine("The Folder is created Sucessfully");
}
else
{
Console.WriteLine("The Folder already exists");
}
DirectoryInfo dInfo = new DirectoryInfo(file);
DirectorySecurity dSecurity = dInfo.GetAccessControl();
dSecurity.AddAccessRule(new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), FileSystemRights.FullControl, InheritanceFlags.ObjectInherit | InheritanceFlags.ContainerInherit, PropagationFlags.NoPropagateInherit, AccessControlType.Allow));
dInfo.SetAccessControl(dSecurity);
}
string fullPath = directory + TEMP_FILE;
fullPath를 얻기 위해 문자열을 연결하는 대신 Path.Combine 메서드를 사용하십시오.Path.Combine(directory, TEMP_FILE)
- nomail