56

以下のような方法でファイルにデータを書き込むプログラムを手に入れました。


public void ExportToFile(string filename)
{
     using(FileStream fstream = new FileStream(filename,FileMode.Create))
     using (TextWriter writer = new StreamWriter(fstream))
     {
         // try catch block for write permissions 
         writer.WriteLine(text);


     }
}

プログラムを実行すると私はエラーが出ます:

未処理の例外:System.UnauthorizedAccessException:パス 'mypath'へのアクセスが拒否されました。      System.IO .__ Error.WinIOError(Int32エラーコード、文字列maybeFullPath)      System.IO.FileStream.Init(Stringパス、FileModeモード、FileAccessアクセス、   nt32権限、Boolean useRights、FileShare共有、Int32 bufferSize、FileOptions   オプション、SECURITY_ATTRIBUTES secAttrs、String msgPath、Boolean bFromProxy)      System.IO.FileStream..ctor(Stringパス、FileModeモード、FileAccessアクセス)   FileShare共有、Int32 bufferSize、FileOptionsオプション、文字列msgPath、Boolea   bFromProxy)

質問:これを把握するために必要なコードは何ですか?また、どのようにアクセスを許可するのですか?

8 답변


63

更新:

に基づいてコードを修正しましたこの答え時代遅れのメソッドを取り除くために。

これを確認するには、Security名前空間を使用できます。

public void ExportToFile(string filename)
{
    var permissionSet = new PermissionSet(PermissionState.None);    
    var writePermission = new FileIOPermission(FileIOPermissionAccess.Write, filename);
    permissionSet.AddPermission(writePermission);

    if (permissionSet.IsSubsetOf(AppDomain.CurrentDomain.PermissionSet))
    {
        using (FileStream fstream = new FileStream(filename, FileMode.Create))
        using (TextWriter writer = new StreamWriter(fstream))
        {
            // try catch block for write permissions 
            writer.WriteLine("sometext");


        }
    }
    else
    {
        //perform some recovery action here
    }

}

それらの許可を得る限りでは、あなたはどういうわけかあなたにそれをするようにユーザに依頼しなければならないでしょう。あなたがプログラム的にこれを行うことができれば、それから私達全員は困っているでしょう;)


  • このソリューションは機能しません、SecurityManager.IsGrantedはファイルに書き込み権限がないにもかかわらずtrueを返します(Win XP SP3) - Thomas Levesque
  • ローカルの管理者として実行していますか、それともアクセス権を持たないより特権の低いユーザーとして実行していますか。 - Josh
  • SecurityManager.IsGrantedはObsoleteとされています。この答えは永遠に働かないかもしれません。 - MarkPflug
  • @ジェトン - あなたが探しているSecurityManager.IsGranted方法。それは使用することを支持して4.0で廃止されましたPermissionSets。上のコードはそれほど変わってはいけませんが、PermissionSet一度に確認できるのは1つの権限だけです。 - Josh
  • @JoshあなたのPCでこれを試してみてください...新しいフォルダを作成して(それが管理者、フルコントロールを持っていること、そしてあなたがAdministratorsグループの一員であることを確認してください)自分の権限を編集して、書き込みを拒否にします。管理者が書き込みアクセス権を持っているため、書き込みのためにTrueが返されます。一方、Denyはアカウントエントリから優先されます。したがって、あなたの方法は私のために動作しません...下記の私の答えを参照してください。 - MaxOvrdrv

30

あなたのコードが次のことをしたとき:

  1. 現在のユーザーが何かをする権限を持っていることを確認します。
  2. 1で確認した資格を必要とするアクションを実行します。

あなたはパーミッションが変更されるリスクを冒します。1そして2実行時にシステムで他に何が起きるのか予測できないためです。したがって、コードは次のような状況に対処する必要があります。UnauthorisedAccessException以前に権限を確認した場合でも、がスローされます。

そのことに注意してください保安管理者classはCASのアクセス許可を確認するために使用され、現在のユーザーが指定された場所に(ACLおよびACEを介して)書き込みアクセス権を持っているかどうかを実際には確認しません。など、IsGrantedローカルで実行しているアプリケーションに対しては常にtrueを返します。

(に由来するジョシュの例):

//1. Provide early notification that the user does not have permission to write.
FileIOPermission writePermission = new FileIOPermission(FileIOPermissionAccess.Write, filename);
if(!SecurityManager.IsGranted(writePermission))
{
    //No permission. 
    //Either throw an exception so this can be handled by a calling function
    //or inform the user that they do not have permission to write to the folder and return.
}

//2. Attempt the action but handle permission changes.
try
{
    using (FileStream fstream = new FileStream(filename, FileMode.Create))
    using (TextWriter writer = new StreamWriter(fstream))
    {
        writer.WriteLine("sometext");
    }
}
catch (UnauthorizedAccessException ex)
{
    //No permission. 
    //Either throw an exception so this can be handled by a calling function
    //or inform the user that they do not have permission to write to the folder and return.
}

トリッキーですお勧めしません生のACLに基づいてフォルダから有効なアクセス許可をプログラム的に計算しようとします。System.Security.AccessControlクラス)。 Stack Overflowやその他のWebに関する他の回答では、許可が許可されているかどうかを知るためにアクションを実行することをお勧めします。このpostはパーミッションの計算を実行するために必要なものをまとめたもので、これをやめさせるには十分なはずです。


  • この哲学はすべてうまくいっていますが、普遍的には機能しません。たとえば、書き込み先のフォルダへのパスをユーザーが選択するダイアログを表示し、候補として適切な初期値をダイアログに追加したい場合は、ターゲットフォルダが作成されないようにします。存在しません。後方互換性の理由から、このデフォルトパスは" C:\< SomeName>"です。ユーザーがそこに書き込めない場合は、AppDataの下のデフォルトにフォールバックしたいです。フォルダ参照ダイアログの初期値を決定するためだけに、フォルダを作成してから削除する方法はありません。 - Roger Sanders
  • @ RogerSanders - 良い点です。 - Iain

8

MaxOvrdrvのその修正版コード

public static bool IsReadable(this DirectoryInfo di)
{
    AuthorizationRuleCollection rules;
    WindowsIdentity identity;
    try
    {
        rules = di.GetAccessControl().GetAccessRules(true, true, typeof(SecurityIdentifier));
        identity = WindowsIdentity.GetCurrent();
    }
    catch (UnauthorizedAccessException uae)
    {
        Debug.WriteLine(uae.ToString());
        return false;
    }

    bool isAllow = false;
    string userSID = identity.User.Value;

    foreach (FileSystemAccessRule rule in rules)
    {
        if (rule.IdentityReference.ToString() == userSID || identity.Groups.Contains(rule.IdentityReference))
        {
            if ((rule.FileSystemRights.HasFlag(FileSystemRights.Read) ||
                rule.FileSystemRights.HasFlag(FileSystemRights.ReadAttributes) ||
                rule.FileSystemRights.HasFlag(FileSystemRights.ReadData)) && rule.AccessControlType == AccessControlType.Deny)
                return false;
            else if ((rule.FileSystemRights.HasFlag(FileSystemRights.Read) &&
                rule.FileSystemRights.HasFlag(FileSystemRights.ReadAttributes) &&
                rule.FileSystemRights.HasFlag(FileSystemRights.ReadData)) && rule.AccessControlType == AccessControlType.Allow)
                isAllow = true;

        }
    }
    return isAllow;
}

public static bool IsWriteable(this DirectoryInfo me)
{
    AuthorizationRuleCollection rules;
    WindowsIdentity identity;
    try
    {
        rules = me.GetAccessControl().GetAccessRules(true, true, typeof(System.Security.Principal.SecurityIdentifier));
        identity = WindowsIdentity.GetCurrent();
    }
    catch (UnauthorizedAccessException uae)
    {
        Debug.WriteLine(uae.ToString());
        return false;
    }

    bool isAllow = false;
    string userSID = identity.User.Value;

    foreach (FileSystemAccessRule rule in rules)
    {
        if (rule.IdentityReference.ToString() == userSID || identity.Groups.Contains(rule.IdentityReference))
        {
            if ((rule.FileSystemRights.HasFlag(FileSystemRights.Write) ||
                rule.FileSystemRights.HasFlag(FileSystemRights.WriteAttributes) ||
                rule.FileSystemRights.HasFlag(FileSystemRights.WriteData) ||
                rule.FileSystemRights.HasFlag(FileSystemRights.CreateDirectories) ||
                rule.FileSystemRights.HasFlag(FileSystemRights.CreateFiles)) && rule.AccessControlType == AccessControlType.Deny)
                return false;
            else if ((rule.FileSystemRights.HasFlag(FileSystemRights.Write) &&
                rule.FileSystemRights.HasFlag(FileSystemRights.WriteAttributes) &&
                rule.FileSystemRights.HasFlag(FileSystemRights.WriteData) &&
                rule.FileSystemRights.HasFlag(FileSystemRights.CreateDirectories) &&
                rule.FileSystemRights.HasFlag(FileSystemRights.CreateFiles)) && rule.AccessControlType == AccessControlType.Allow)
                isAllow = true;

        }
    }
    return isAllow;
}


  • これは本当にうまくいきました。ありがとうございます。 - Smartis
  • これは本当にうまくいった!私はアプリケーションではなくloged inユーザーに基づいて選択された答えがアクセス許可をチェックすると思います。 - ibocon
  • これは動作します。私はチェックしたC:\Program Files\...管理者として私のアプリケーションを実行せずにフォルダ。IsWriteable()その場合はfalseを返します。 - arnobpl

6

すみません、しかし前の解決策のどれも私を助けませんでした。私は両方の側をチェックする必要があります:SecurityManagerとSOパーミッション。私はJoshコードと私の答えで多くのことを学びましたが、私はRakeshコードを使う必要があると思います(彼のおかげで)。たった一つのバグ:私は彼がAllowだけをチェックし、Denyパーミッションをチェックしないことを発見しました。だから私の提案は:

        string folder;
        AuthorizationRuleCollection rules;
        try {
            rules = Directory.GetAccessControl(folder)
                .GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount));
        } catch(Exception ex) { //Posible UnauthorizedAccessException
            throw new Exception("No permission", ex);
        }

        var rulesCast = rules.Cast<FileSystemAccessRule>();
        if(rulesCast.Any(rule => rule.AccessControlType == AccessControlType.Deny)
            || !rulesCast.Any(rule => rule.AccessControlType == AccessControlType.Allow))
            throw new Exception("No permission");

        //Here I have permission, ole!



4

これはクローズされていないので、私は何かが彼らのためにきちんと動いていることを望んでいる人のために新しいエントリーを提出したいと思います...そしてコード自体をデバッグして見つけるためにDirectoryServicesを使って使用する適切なコードは、ここで私はあらゆる状況で私のために働くことがわかったものです...私のソリューションはDirectoryInfoオブジェクトを拡張することに注意してください...:

    public static bool IsReadable(this DirectoryInfo me)
    {

        AuthorizationRuleCollection rules;
        WindowsIdentity identity;
        try
        {
            rules = me.GetAccessControl().GetAccessRules(true, true, typeof(System.Security.Principal.SecurityIdentifier));
            identity = WindowsIdentity.GetCurrent();
        }
        catch (Exception ex)
        { //Posible UnauthorizedAccessException
            return false;
        }

        bool isAllow=false;
        string userSID = identity.User.Value;

        foreach (FileSystemAccessRule rule in rules)
        {
            if (rule.IdentityReference.ToString() == userSID || identity.Groups.Contains(rule.IdentityReference))
            {
                if ((rule.FileSystemRights.HasFlag(FileSystemRights.Read) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.ReadAndExecute) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.ReadAttributes) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.ReadData) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.ReadExtendedAttributes) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.ReadPermissions)) && rule.AccessControlType == AccessControlType.Deny)
                    return false;
                else if ((rule.FileSystemRights.HasFlag(FileSystemRights.Read) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.ReadAndExecute) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.ReadAttributes) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.ReadData) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.ReadExtendedAttributes) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.ReadPermissions)) && rule.AccessControlType == AccessControlType.Allow)
                    isAllow = true;
            }
        }

        return isAllow;
    }

    public static bool IsWriteable(this DirectoryInfo me)
    {
        AuthorizationRuleCollection rules;
        WindowsIdentity identity;
        try
        {
            rules = me.GetAccessControl().GetAccessRules(true, true, typeof(System.Security.Principal.SecurityIdentifier));
            identity = WindowsIdentity.GetCurrent();
        }
        catch (Exception ex)
        { //Posible UnauthorizedAccessException
            return false;
        }

        bool isAllow = false;
        string userSID = identity.User.Value;

        foreach (FileSystemAccessRule rule in rules)
        {
            if (rule.IdentityReference.ToString() == userSID || identity.Groups.Contains(rule.IdentityReference))
            {
                if ((rule.FileSystemRights.HasFlag(FileSystemRights.Write) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.WriteAttributes) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.WriteData) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.WriteExtendedAttributes) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.CreateDirectories) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.CreateFiles)) && rule.AccessControlType == AccessControlType.Deny)
                    return false;
                else if ((rule.FileSystemRights.HasFlag(FileSystemRights.Write) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.WriteAttributes) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.WriteData) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.WriteExtendedAttributes) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.CreateDirectories) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.CreateFiles)) && rule.AccessControlType == AccessControlType.Allow)
                    isAllow = true;
            }
        }

        return me.IsReadable() && isAllow;
    }


  • 私は2つ(IMO)の可能な改善に気づきました。 1番目に、IsReadableの開始時にディレクトリ(me.Exists)の存在を確認します。 2番目のIsWritable内で、IsReadableチェックを一番上に移動します。また、状況によってはファイルを書き込むことができてもファイルを読み取ることができないため、2つの方法を "リンク解除"したままにしたいことがあります。 - K Kimble
  • また、メソッド呼び出しの外側の列挙型を組み合わせて静的にすることでうまくいくと私は信じています。public static FileSystemRights _ReadRights = FileSystemRights.Read | FileSystemRights.ReadAndExecute | FileSystemRights.ReadAttributes | FileSystemRights.ReadData | FileSystemRights.ReadExtendedAttributes | FileSystemRights.ReadPermissions;テスト呼び出しを単純化します。if(rule.FileSystemRights.HasFlag(_ReadRights)&amp;&amp;&amp; rule.AccessControlType == AccessControlType.Deny) - K Kimble
  • また動作しません。解決策はありませんか? - Pedro77
  • こんにちは@ Pedro77 - おさる...あなたはどんなOSを使っていますか?私はこれを使っていて、XP、Vista、そしてWin7でそれをテストしてきました、そして3つすべてが完璧に動作しています。あなたはWindows 8にいますか? - MaxOvrdrv
  • Win7 x 64管理者としてログインし、実行されていないアプリはadmでした。 - Pedro77

3

これらのどれも私のために働きませんでした..彼らはそうでなくても、彼らは本当のように戻ります。問題は、現在のプロセスのユーザー権限に対して利用可能な権限をテストする必要があるということです。これはファイル作成権限をテストするためのもので、書き込みアクセスをテストするにはFileSystemRights句を 'Write'に変更するだけです。

/// <summary>
/// Test a directory for create file access permissions
/// </summary>
/// <param name="DirectoryPath">Full directory path</param>
/// <returns>State [bool]</returns>
public static bool DirectoryCanCreate(string DirectoryPath)
{
    if (string.IsNullOrEmpty(DirectoryPath)) return false;

    try
    {
        AuthorizationRuleCollection rules = Directory.GetAccessControl(DirectoryPath).GetAccessRules(true, true, typeof(System.Security.Principal.SecurityIdentifier));
        WindowsIdentity identity = WindowsIdentity.GetCurrent();

        foreach (FileSystemAccessRule rule in rules)
        {
            if (identity.Groups.Contains(rule.IdentityReference))
            {
                if ((FileSystemRights.CreateFiles & rule.FileSystemRights) == FileSystemRights.CreateFiles)
                {
                    if (rule.AccessControlType == AccessControlType.Allow)
                        return true;
                }
            }
        }
    }
    catch {}
    return false;
}


  • これは断然最良の答えです...しかし、あなたはDenyが2つのブール値を使用することによって許可よりも優先されることを考慮に入れるためにあなたのコードを修正するべきです... - MaxOvrdrv
  • C:\にはtrueを返しますが、C:\にファイルを作成しようとすると例外が発生します。 - Pedro77

2

次のコードブロックを試して、ディレクトリに書き込みアクセス権があるかどうかを確認できます。

FileSystemAccessRuleを確認します。

           string directoryPath = "C:\\XYZ"; //folderBrowserDialog.SelectedPath;
           bool isWriteAccess = false;
           try
           {
              AuthorizationRuleCollection collection = Directory.GetAccessControl(directoryPath).GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount));
              foreach (FileSystemAccessRule rule in collection)
              {
                 if (rule.AccessControlType == AccessControlType.Allow)
                 {
                    isWriteAccess = true;
                    break;
                 }
              }
           }
           catch (UnauthorizedAccessException ex)
           {
              isWriteAccess = false;
           }
           catch (Exception ex)
           {
              isWriteAccess = false;
           }
           if (!isWriteAccess)
           {
             //handle notifications                 
           }


  • それは動作しません。 C:\にはtrueを返しますが、C:\にファイルを作成しようとすると例外が発生します。 - Pedro77

0

うわー...このスレッドには低レベルのセキュリティコードがたくさんあります - そのほとんどは私にはうまくいきませんでした - 私はその過程で多くを学びましたが。私が学んだことの1つは、このコードの大部分は、ユーザーごとのアクセス権を求めるアプリケーションを対象としていないということです。これは、管理者がプログラムで権利を変更したいためです。ではないよいこと。開発者として、私はAdministratorとして実行することによって「簡単な方法」を使用することはできません - 私はコードを実行するマシン上の1人でも、ユーザーでもありません。 - それらは私の状況のためのものではなく、そしておそらく大部分のランクおよびファイル開発者のためのものでもないでしょう。

この種の質問のほとんどのポスターのように - 私も最初はそれが「ハッキー」だと感じました - それ以来私はそれを試してみることは完全に大丈夫だと思いました。私が得た情報では、その権利が実際に何であるのかがわかりませんでした。以下のコード - やった。

  Private Function CheckUserAccessLevel(folder As String) As Boolean
Try
  Dim newDir As String = String.Format("{0}{1}{2}",
                                       folder,
                                       If(folder.EndsWith("\"),
                                          "",
                                          "\"),
                                       "LookWhatICanDo")
  Dim lookWhatICanDo = Directory.CreateDirectory(newDir)

  Directory.Delete(newDir)
  Return True

Catch ex As Exception
  Return False
End Try

終了機能

リンクされた質問


関連する質問

最近の質問