使用英语阅读

通过


Windows 窗体中更加安全的文件和数据访问

.NET Framework 使用权限来帮助保护资源和数据。 应用程序可以读取或写入数据的位置取决于授予应用程序的权限。 当应用程序在部分信任环境中运行时,可能无权访问数据,或者可能需要更改访问数据的方式。

遇到安全限制时,你有两个选择:断言该权限(假设已将该权限授予你的应用程序),或者使用编写为用于部分信任中的功能版本。 以下各节探讨如何使用文件、数据库和在部分信任环境中运行的应用程序中的注册表访问。

备注

默认情况下,生成 ClickOnce 部署的工具默认这些部署从在其上运行的计算机请求完全信任。 如果你决定想要在部分信任中运行的附加安全优势,则必须在 Visual Studio 或 Windows SDK 工具之一(Mage.exe 或 MageUI.exe)中更改此默认值。 有关 Windows 窗体安全性以及如何确定应用程序的相应信任级别的详细信息,请参阅 Windows 窗体概述中的 安全性。

文件访问

FileIOPermission 类控制 .NET Framework 中的文件和文件夹访问权限。 默认情况下,安全系统不会向部分信任环境(如本地 Intranet 和 Internet 区域)授予 FileIOPermission。 但是,如果修改应用程序的设计或使用不同的方法来访问文件,则要求文件访问的应用程序仍可在这些环境中正常运行。 默认情况下,将向本地 Intranet 区域授予以下权限:具有相同的站点访问权限和相同的目录访问权限、连回其源站点、从其安装目录进行读取。 默认情况下,Internet 区域仅被授予连接回其源站点的权限。

用户指定的文件

处理没有文件访问权限的一种方法是提示用户使用 OpenFileDialogSaveFileDialog 类提供特定文件信息。 此用户交互有助于确保应用程序无法恶意加载专用文件或覆盖重要文件。 OpenFileOpenFile 方法通过打开用户指定的文件的文件流来提供读取和写入文件访问权限。 这些方法还通过掩盖文件的路径来帮助保护用户的文件。

备注

这些权限因应用程序位于 Internet 区域还是 Intranet 区域而异。 Internet 区域应用程序只能使用 OpenFileDialog,而 Intranet 应用程序具有不受限制的文件对话框权限。

FileDialogPermission 类指定应用程序可以使用的文件对话框的类型。 下表显示使用每种 FileDialog 类所必须具有的值。

所需的访问值
OpenFileDialog Open
SaveFileDialog Save

备注

在实际调用 OpenFile 方法之前,不会请求特定权限。

显示文件对话框的权限不会授予应用程序对 FileDialogOpenFileDialogSaveFileDialog 类的所有成员的完全访问权限。 有关调用每个方法所需的确切权限,请参阅 .NET Framework 类库文档中该方法的参考主题。

下面的代码示例使用 OpenFile 方法将用户指定的文件打开到 RichTextBox 控件中。 此示例需要 FileDialogPermission 和关联的 Open 枚举值。 该示例演示如何处理 SecurityException 以确定是否应禁用保存功能。 此示例要求 Form 具有名为 ButtonOpenButton 控件和名为 RtfBoxMainRichTextBox 控件。

备注

示例中未显示保存功能的编程逻辑。

Private Sub ButtonOpen_Click(ByVal sender As System.Object, _  
    ByVal e As System.EventArgs) Handles ButtonOpen.Click
  
    Dim editingFileName as String = ""  
    Dim saveAllowed As Boolean = True  
  
    ' Displays the OpenFileDialog.  
    If (OpenFileDialog1.ShowDialog() = DialogResult.OK) Then  
        Dim userStream as System.IO.Stream  
        Try
            ' Opens the file stream for the file selected by the user.  
            userStream =OpenFileDialog1.OpenFile()
            Me.RtfBoxMain.LoadFile(userStream, _  
                RichTextBoxStreamType.PlainText)  
        Finally  
            userStream.Close()  
        End Try  
  
        ' Tries to get the file name selected by the user.  
        ' Failure means that the application does not have  
        ' unrestricted permission to the file.  
        Try
            editingFileName = OpenFileDialog1.FileName  
        Catch ex As Exception  
            If TypeOf ex Is System.Security.SecurityException Then
                ' The application does not have unrestricted permission
                ' to the file so the save feature will be disabled.  
                saveAllowed = False
            Else
                Throw ex  
            End If  
        End Try  
    End If  
End Sub  
private void ButtonOpen_Click(object sender, System.EventArgs e)
{  
    String editingFileName = "";  
    Boolean saveAllowed = true;  
  
    // Displays the OpenFileDialog.  
    if (openFileDialog1.ShowDialog() == DialogResult.OK)
    {  
        // Opens the file stream for the file selected by the user.  
        using (System.IO.Stream userStream = openFileDialog1.OpenFile())
        {  
            this.RtfBoxMain.LoadFile(userStream,  
                RichTextBoxStreamType.PlainText);  
            userStream.Close();  
        }  
  
        // Tries to get the file name selected by the user.  
        // Failure means that the application does not have  
        // unrestricted permission to the file.  
        try
        {  
            editingFileName = openFileDialog1.FileName;  
        }
        catch (Exception ex)
        {  
            if (ex is System.Security.SecurityException)
            {  
                // The application does not have unrestricted permission
                // to the file so the save feature will be disabled.  
                saveAllowed = false;
            }
            else
            {  
                throw ex;  
            }  
        }  
    }  
}  

备注

在 Visual C# 中,确保添加代码以启用事件处理程序。 通过使用上一示例中的代码,以下代码演示如何启用事件处理程序。this.ButtonOpen.Click += newSystem.Windows.Forms.EventHandler(this.ButtonOpen_Click);

其他文件

有时,需要读取或写入用户未指定的文件,例如,必须保留应用程序设置。 在本地 Intranet 和 Internet 区域中,应用程序将无权将数据存储在本地文件中。 但是,应用程序将能够将数据存储在隔离存储中。 独立存储是一个抽象数据隔离舱(而不是特定存储位置),其中包含一个或多个隔离存储文件(称为存储),其中包含存储数据的实际目录位置。 不需要 FileIOPermission 等文件访问权限;相反,IsolatedStoragePermission 类控制隔离存储的权限。 默认情况下,在本地 Intranet 和 Internet 区域中运行的应用程序可以使用隔离存储来存储数据;但是,磁盘配额等设置可能会有所不同。 有关隔离存储的详细信息,请参阅 独立存储

以下示例使用独立存储将数据写入存储中的文件。 此示例需要 IsolatedStorageFilePermissionDomainIsolationByUser 枚举值。 该示例演示如何将 Button 控件的某些属性值读取和写入隔离存储中的文件。 Read 函数将在应用程序启动后调用,Write 函数将在应用程序结束之前调用。 该示例要求 ReadWrite 函数作为包含名为 MainButtonButton 控件 Form 的成员存在。

' Reads the button options from the isolated storage. Uses Default values
' for the button if the options file does not exist.  
Public Sub Read()
    Dim isoStore As System.IO.IsolatedStorage.IsolatedStorageFile = _  
        System.IO.IsolatedStorage.IsolatedStorageFile. _
        GetUserStoreForDomain()  
  
    Dim filename As String = "options.txt"  
    Try  
        ' Checks to see if the options.txt file exists.  
        If (isoStore.GetFileNames(filename).GetLength(0) <> 0) Then  
  
            ' Opens the file because it exists.  
            Dim isos As New System.IO.IsolatedStorage.IsolatedStorageFileStream _
                 (filename, IO.FileMode.Open,isoStore)  
            Dim reader as System.IO.StreamReader  
            Try
                reader = new System.IO.StreamReader(isos)  
  
                ' Reads the values stored.  
                Dim converter As System.ComponentModel.TypeConverter  
                converter = System.ComponentModel.TypeDescriptor.GetConverter _
                    (GetType(Color))  
  
                Me.MainButton.BackColor = _
                        CType(converter.ConvertFromString _
                         (reader.ReadLine()), Color)  
                me.MainButton.ForeColor = _  
                        CType(converter.ConvertFromString _
                         (reader.ReadLine()), Color)  
  
                converter = System.ComponentModel.TypeDescriptor.GetConverter _
                    (GetType(Font))  
                me.MainButton.Font = _  
                        CType(converter.ConvertFromString _
                         (reader.ReadLine()), Font)  
  
            Catch ex As Exception  
                Debug.WriteLine("Cannot read options " + _  
                    ex.ToString())  
            Finally  
                reader.Close()  
            End Try  
        End If  
  
    Catch ex As Exception  
        Debug.WriteLine("Cannot read options " + ex.ToString())  
    End Try  
End Sub  
  
' Writes the button options to the isolated storage.  
Public Sub Write()
    Dim isoStore As System.IO.IsolatedStorage.IsolatedStorageFile = _  
        System.IO.IsolatedStorage.IsolatedStorageFile. _
        GetUserStoreForDomain()  
  
    Dim filename As String = "options.txt"  
    Try
        ' Checks if the file exists, and if it does, tries to delete it.  
        If (isoStore.GetFileNames(filename).GetLength(0) <> 0) Then  
            isoStore.DeleteFile(filename)  
        End If  
    Catch ex As Exception  
        Debug.WriteLine("Cannot delete file " + ex.ToString())  
    End Try  
  
    ' Creates the options.txt file and writes the button options to it.  
    Dim writer as System.IO.StreamWriter  
    Try
        Dim isos As New System.IO.IsolatedStorage.IsolatedStorageFileStream _
             (filename, IO.FileMode.CreateNew, isoStore)  
  
        writer = New System.IO.StreamWriter(isos)  
        Dim converter As System.ComponentModel.TypeConverter  
  
        converter = System.ComponentModel.TypeDescriptor.GetConverter _
           (GetType(Color))  
        writer.WriteLine(converter.ConvertToString( _  
            Me.MainButton.BackColor))  
        writer.WriteLine(converter.ConvertToString( _  
            Me.MainButton.ForeColor))  
  
        converter = System.ComponentModel TypeDescriptor.GetConverter _
           (GetType(Font))  
        writer.WriteLine(converter.ConvertToString( _  
            Me.MainButton.Font))  
  
    Catch ex as Exception  
        Debug.WriteLine("Cannot write options " + ex.ToString())  
  
    Finally  
        writer.Close()  
    End Try  
End Sub  
// Reads the button options from the isolated storage. Uses default values
// for the button if the options file does not exist.  
public void Read()
{  
    System.IO.IsolatedStorage.IsolatedStorageFile isoStore =
        System.IO.IsolatedStorage.IsolatedStorageFile.  
        GetUserStoreForDomain();  
  
    string filename = "options.txt";  
    try  
    {  
        // Checks to see if the options.txt file exists.  
        if (isoStore.GetFileNames(filename).GetLength(0) != 0)
        {  
            // Opens the file because it exists.  
            System.IO.IsolatedStorage.IsolatedStorageFileStream isos =
                new System.IO.IsolatedStorage.IsolatedStorageFileStream  
                    (filename, System.IO.FileMode.Open,isoStore);  
            System.IO.StreamReader reader = null;  
            try
            {  
                reader = new System.IO.StreamReader(isos);  
  
                // Reads the values stored.  
                TypeConverter converter ;  
                converter = TypeDescriptor.GetConverter(typeof(Color));  
  
                this.MainButton.BackColor =
                 (Color)(converter.ConvertFromString(reader.ReadLine()));  
                this.MainButton.ForeColor =
                 (Color)(converter.ConvertFromString(reader.ReadLine()));  
  
                converter = TypeDescriptor.GetConverter(typeof(Font));  
                this.MainButton.Font =
                  (Font)(converter.ConvertFromString(reader.ReadLine()));  
            }  
            catch (Exception ex)  
            {
                System.Diagnostics.Debug.WriteLine  
                     ("Cannot read options " + ex.ToString());  
            }  
            finally  
            {  
                reader.Close();  
            }  
        }  
    }
    catch (Exception ex)
    {  
        System.Diagnostics.Debug.WriteLine  
            ("Cannot read options " + ex.ToString());  
    }  
}  
  
// Writes the button options to the isolated storage.  
public void Write()
{  
    System.IO.IsolatedStorage.IsolatedStorageFile isoStore =
        System.IO.IsolatedStorage.IsolatedStorageFile.  
        GetUserStoreForDomain();  
  
    string filename = "options.txt";  
    try
    {  
        // Checks if the file exists and, if it does, tries to delete it.  
        if (isoStore.GetFileNames(filename).GetLength(0) != 0)
        {  
            isoStore.DeleteFile(filename);  
        }  
    }  
    catch (Exception ex)
    {  
        System.Diagnostics.Debug.WriteLine  
            ("Cannot delete file " + ex.ToString());  
    }  
  
    // Creates the options file and writes the button options to it.  
    System.IO.StreamWriter writer = null;  
    try
    {  
        System.IO.IsolatedStorage.IsolatedStorageFileStream isos = new
            System.IO.IsolatedStorage.IsolatedStorageFileStream(filename,
            System.IO.FileMode.CreateNew,isoStore);  
  
        writer = new System.IO.StreamWriter(isos);  
        TypeConverter converter ;  
  
        converter = TypeDescriptor.GetConverter(typeof(Color));  
        writer.WriteLine(converter.ConvertToString(  
            this.MainButton.BackColor));  
        writer.WriteLine(converter.ConvertToString(  
            this.MainButton.ForeColor));  
  
        converter = TypeDescriptor.GetConverter(typeof(Font));  
        writer.WriteLine(converter.ConvertToString(  
            this.MainButton.Font));  
  
    }  
    catch (Exception ex)  
    {
        System.Diagnostics.Debug.WriteLine  
           ("Cannot write options " + ex.ToString());  
    }  
    finally  
    {  
        writer.Close();  
    }  
}  

数据库访问

访问数据库所需的权限因数据库提供程序而异;但是,只有具有适当权限运行的应用程序才能通过数据连接访问数据库。 有关访问数据库所需的权限的详细信息,请参阅 代码访问安全和 ADO.NET

如果由于希望应用程序在部分信任中运行而无法直接访问数据库,则可以使用 Web 服务作为访问数据的替代方法。 Web 服务是一种可通过网络以编程方式访问的软件。 使用 Web 服务,应用程序可以跨代码组区域共享数据。 默认情况下,本地 Intranet 和 Internet 区域中的应用程序有权访问其源站点,从而使它们能够调用在同一服务器上托管的 Web 服务。 有关详细信息,请参阅 ASP.NET AJAX 或 Windows Communication Foundation中的 Web 服务。

注册表访问

RegistryPermission 类控制对操作系统注册表的访问。 默认情况下,只有在本地运行的应用程序才能访问注册表。 RegistryPermission 仅授予应用程序尝试注册表访问权限的权限;它不能保证访问会成功,因为操作系统仍然在注册表上强制实施安全性。

由于无法在部分信任下访问注册表,因此可能需要查找存储数据的其他方法。 存储应用程序设置时,请使用独立存储而不是注册表。 独立存储还可用于存储其他特定于应用程序的文件。 还可以存储有关服务器或源站点的全局应用程序信息,因为默认情况下,应用程序被授予访问其源站点的权限。

另请参阅