首页 > 解决方案 > VB.NET - 如何以编程方式将身份验证传递给服务器 - 如何访问需要身份验证的服务器上的文件

问题描述

我的目标:

我正在尝试访问我们网络上服务器的 C 盘,目的是搜索某个文件扩展名并返回这些文件的路径。我在这里找到了完美运行的代码,但前提是我正在搜索我的本地计算机,或者我已经通过身份验证的服务器的 IP;当我尝试将代码运行到我尚未对其进行身份验证的服务器的 IP 时,它不起作用。

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Cursor = Cursors.WaitCursor
    DirSearch("\\10.0.15.87\c$")
    Cursor = Cursors.Default
End Sub

Public Sub DirSearch(ByVal sDir As String)
    Try
        For Each dir As String In Directory.GetDirectories(sDir)
            For Each file In Directory.GetFiles(dir, "myfile.extension")
                MsgBox(file)
            Next
            DirSearch(dir)
        Next
    Catch ex As Exception
        Debug.WriteLine(ex.Message)
    End Try
End Sub

当我运行代码时:

我相信代码执行完成;光标变为 WaitCursor 大约半秒钟,然后恢复正常,此时不会抛出任何错误,一切都照常进行。如果我将“10.0.15.87”更改为“10.0.15.81”(我已经手动对其进行了身份验证),那么我会弹出一些带有文件路径的 MsgBox。(我确信问题不在于搜索文件,我知道它适用于其他 ip,并且我正在搜索的文件位于 10.0.15.87 的 c 驱动器中 - 我相信我只需要通过身份验证。 )

这是我尝试手动浏览到 ip 87 时发生的情况:

在此处输入图像描述

关于 10.0.15.87 的信息:

在尝试访问服务器之前如何通过身份验证?

标签: vb.netauthenticationserverconnection

解决方案


更新:我相信我找到了最简单和最一致的方法,方法 2 和 3 可能会或可能不会始终如一地工作我发现。

方法 1 - 调用网络使用(一致和跨域工作)

网络使用命令允许您通过命令提示符将凭据存储到共享,并且您可以非常轻松地从 .NET 调用它。

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

    Dim proc As New Process
    proc.StartInfo.FileName = "net"
    proc.StartInfo.UseShellExecute = True
    proc.EnableRaisingEvents = False

    Dim server As String = "Server"
    Dim user As String = "User"
    Dim pass As String = "Pass"

    If EnsureConnection(server) Then
        proc.StartInfo.Arguments = "use \\" & server & "\IPC$ /u:" & server & "\" & user & " " & pass
        proc.Start()
    End If
End Sub

Function EnsureConnection(server As String)
    'Give more or less ping attempts depending on how reliable your connection is.
    'I have found that one ping can give false negative easily even on reliable connections
    If My.Computer.Network.Ping(server) Then
        Return True
    ElseIf My.Computer.Network.Ping(server) Then
        Return True
    Else
        Return False
    End If
End Function

此方法会将凭据存储在机器上,直到机器关闭或重新启动,并且用户也将在程序之外进行身份验证。如果不希望这样做,您可以在程序完成后立即使用命令的“/delete”开关将其删除。

方法 2 - 在 MPR.DLL 中使用函数

我最终找到了另一个问题的答案。这是对我有用的方法。这是集成到我的项目中的样子:

Imports System.IO    
Imports System.Runtime.InteropServices

Public Class Form1 
    Dim user As String
    Dim pass As String
    Dim path As String

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Cursor = Cursors.WaitCursor
        user = "UsernameString"
        pass = "PasswordString"
        path = "\\10.0.15.87\c$"
        MPRAuth()
        DirSearch(path)
        Cursor = Cursors.Default
    End Sub

    Private Sub MPRAuth()
        Dim nr As New NETRESOURCE
        nr.dwType = RESOURCETYPE_DISK
        nr.lpRemoteName = path
        If WNetAddConnection2(nr, pass, user, 0) <> NO_ERROR Then
            Throw New Exception("WNetAddConnection2 failed.")
        End If
        If WNetCancelConnection2(path, 0, True) <> NO_ERROR Then
            Throw New Exception("WNetCancelConnection2 failed.")
        End If
    End Sub

    Public Sub DirSearch(ByVal sDir As String)
        Try
            For Each dir As String In Directory.GetDirectories(sDir)
                Try
                    For Each file In Directory.GetFiles(dir, "*.exe")
                        MsgBox(file)
                    Next
                Catch ex As Exception
                    Debug.WriteLine(ex.Message)
                End Try
                DirSearch(dir)
            Next
        Catch ex As Exception
            Debug.WriteLine(ex.Message)
        End Try
    End Sub

    <StructLayout(LayoutKind.Sequential)>
    Private Structure NETRESOURCE
        Public dwScope As UInteger
        Public dwType As UInteger
        Public dwDisplayType As UInteger
        Public dwUsage As UInteger
        <MarshalAs(UnmanagedType.LPTStr)>
        Public lpLocalName As String
        <MarshalAs(UnmanagedType.LPTStr)>
        Public lpRemoteName As String
        <MarshalAs(UnmanagedType.LPTStr)>
        Public lpComment As String
        <MarshalAs(UnmanagedType.LPTStr)>
        Public lpProvider As String
    End Structure

    Private Const NO_ERROR As UInteger = 0
    Private Const RESOURCETYPE_DISK As UInteger = 1

    <DllImport("mpr.dll", CharSet:=CharSet.Auto)>
    Private Shared Function WNetAddConnection2(ByRef lpNetResource As NETRESOURCE, <[In](), MarshalAs(UnmanagedType.LPTStr)> ByVal lpPassword As String, <[In](), MarshalAs(UnmanagedType.LPTStr)> ByVal lpUserName As String, ByVal dwFlags As UInteger) As UInteger
    End Function

    <DllImport("mpr.dll", CharSet:=CharSet.Auto)>
    Private Shared Function WNetCancelConnection2(<[In](), MarshalAs(UnmanagedType.LPTStr)> ByVal lpName As String, ByVal dwFlags As UInteger, <MarshalAs(UnmanagedType.Bool)> ByVal fForce As Boolean) As UInteger
    End Function
End Class

方法 3 - NetworkCredential 和 CredentialCache

此方法将 ip 转换为 URI 并缓存凭据。我无法使这种方法在与我不同域的服务器上工作。

Imports System.Net

Dim builder As New UriBuilder("10.0.15.87")
Dim uri As Uri = builder.Uri
Dim netCred = New NetworkCredential("UsernameString", "PasswordString", "DomainString")
Dim netCache = New CredentialCache()
netCache.Add(uri, "Basic", netCred)
DirSearch("\\10.0.15.87\c$")

方法 2 比方法 2 涉及的内容要少得多,只要我尝试连接的服务器与我在同一个域上,它对我来说就可以正常工作。当我尝试连接到不在域上的服务器时,我收到错误“用户名或密码不正确”,这是不正确的,所以我不确定问题出在哪里 - 也许其他人知道。到目前为止,方法 2 对我来说对任何服务器来说都完美无缺,无论是域还是在运行代码之前手动对其进行了身份验证。希望这对其他人有帮助!


推荐阅读