Acceso a archivos en el servidor mediante la especificación de credenciales
Frecuentes
Visto 4,088 veces
2
Nuestra empresa tiene un servidor de documentos de puntos compartidos donde la UNC se parece a esto: \\theserver.ourdomain.com\rootdirectory
Actualmente, esta unidad está asignada a Z:\ en mi computadora local. Para acceder a Z:\, debe especificar (cada vez que inicie sesión) las credenciales (en nuestro caso, es nuestro nombre de usuario y contraseña con los que iniciamos sesión) para acceder a las carpetas y archivos en el directorio raíz.
Estoy en una situación en la que necesito copiar archivos en el servidor de puntos compartidos. Quiero poder copiar archivos en el servidor sin usar la unidad de red asignada (no tengo que especificar Z:\ en la ruta). ¿Cómo puedo proporcionar credenciales para poder realizar funciones básicas de IO como GetDirectories(), GetFiles(), IO.File.Copy(), etc.?
He investigado las siguientes cosas, pero no he podido hacer que funcionen:
- Logonuser Llamada API especificando el nombre de usuario y la contraseña de texto sin formato, luego tomando el token de esa llamada y suplantando a ese usuario usando una nueva instancia de la clase WindowsIdentity. Pude obtener el token, pero la suplantación no pareció funcionar. Seguía recibiendo errores de acceso denegado.
CredUIPromptForCredentials/CredUIPromptForWindowsCredentials Llamadas API, pero me doy cuenta de que estas son solo para una interfaz de usuario elegante de Windows en la que puede ingresar sus credenciales y en realidad no hacer nada.
<DllImport("advapi32.dll", SetLastError:=True)> _ Private Shared Function LogonUser(lpszUsername As String, lpszDomain As String, _ lpszPassword As String, dwLogonType As Integer, _ dwLogonProvider As Integer, ByRef phToken As IntPtr) As Boolean End Function <DllImport("kernel32.dll", CharSet:=CharSet.Auto)> _ Private Shared Function CloseHandle(handle As IntPtr) As Boolean End Function '// logon types Public Const LOGON32_LOGON_NETWORK As Integer = 3 Public Const LOGON32_LOGON_NEW_CREDENTIALS As Integer = 9 '// logon providers Public Const LOGON32_PROVIDER_WINNT50 As Integer = 3 Public Const LOGON32_PROVIDER_WINNT40 As Integer = 2 Public Const LOGON32_PROVIDER_WINNT35 As Integer = 1 Public Const LOGON32_PROVIDER_DEFAULT As Integer = 0 Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click Dim token = IntPtr.Zero Dim success = LogonUser("username", "domain", "password", _ LOGON32_LOGON_NEW_CREDENTIALS, _ LOGON32_PROVIDER_DEFAULT, token) If Not success Then Me.RaiseLastWin32Error() End If Using identity = New WindowsIdentity(token) Using impersonated = identity.Impersonate() Try Dim info = New DirectoryInfo("\\theserver.ourdomain.com\rootdirectory\") Dim files = info.GetDirectories() Catch ex As Exception Finally impersonated.Undo() End Try If Not CloseHandle(token) Then Me.RaiseLastWin32Error() End If End Using End Using End Sub Private Sub RaiseLastWin32Error() Dim hr = Marshal.GetLastWin32Error() Dim ex = Marshal.GetExceptionForHR(hr) If ex IsNot Nothing Then Throw ex End If Throw New SystemException(String.Format("Call resulted in error code {0}", hr)) End Sub
2 Respuestas
0
Esta no es una respuesta directa a su pregunta, ya que es un enfoque muy diferente. Si no funciona para su situación, disculpe las molestias, pero ¿ha considerado usar los servicios web de SharePoint para cargar los archivos y recuperar información?
Sugiero este enfoque por varias razones:
- El problema que está experimentando puede deberse a que SharePoint implementa WebDav, que podría no ser 100 % compatible con System.IO. No soy un experto en las entrañas aquí, no sé con seguridad la compatibilidad, pero parece plausible.
- La ubicación UNC que tiene se podría convertir fácilmente en una URL que requiere el servicio web.
- Puede configurar las credenciales directamente en el proxy y puede que le resulte más fácil. (aunque hacemos estas llamadas desde otro servidor web, por lo que las credenciales del grupo de aplicaciones en el ejemplo son lo suficientemente buenas para nosotros)
Aquí hay un código desinfectado y simplificado por si acaso:
// location takes the form http://server.name.com/site/library/folder/document.ext
public string UploadDocument(string location, byte[] fileContents)
{
var result = String.empty;
var destination = new string[1];
destination[0] = location;
var fileName = Path.GetFileName(location);
var fieldInfo = new FieldInformation[0];
CopyResult[] copyResults;
_copyService.Url = "http://server.name.com/_vti_bin/Copy.asmx";
_copyService.Credentials = CredentialCache.DefaultCredentials;
_copyService.CopyIntoItems(fileName, destination, fieldInfo, fileContents, out copyResults);
var errorCode = copyResults[0].ErrorCode;
if (errorCode != CopyErrorCode.Success)
{
if (errorCode == CopyErrorCode.DestinationCheckedOut)
result = "File is currently checked out. Please try again later.";
else
result = "Error uploading content.";
}
return result;
}
_copyService es una dependencia que inyectamos donde la implementación en tiempo de ejecución es el proxy generado por las herramientas de Visual Studio desde el servicio web de SharePoint Copy.asmx.
También puede obtener contenido de carpetas y metadatos de documentos mediante el servicio web Lists.asmx. Las mayores desventajas de este enfoque son que consultar la información requiere cierto conocimiento de CAML y procesar los resultados no es tan fácil. Pero los servicios están razonablemente documentados en MSDN y todas las operaciones funcionan en nuestra aplicación.
Respondido el 12 de junio de 12 a las 22:06
Gracias por la respuesta. Puedo acceder a los archivos y directorios a través del código si yo (a través del Explorador) proporciono mi contraseña y nombre de usuario a la unidad de red asignada según lo solicita. También me preocupan los problemas de rendimiento si sigo la ruta que sugieres. - test
Interesante. Tendré curiosidad por encontrar la solución yo mismo entonces, porque veo de dónde vienes en el ángulo de rendimiento. - Arrojar
0
Bueno, pude resolver esto con la ayuda de la API WNetAddConnection2. Esta API también se usa para mapear unidades de red; sin embargo, puede llamar a este método sin especificar una letra de unidad para que solo agregue la conexión.
Digamos, por ejemplo, que tenía la unidad X: asignada a \\servidor\compartir. Digamos también que requiere nombre de usuario y contraseña para acceder a los archivos en el servidor. Cuando reinicie Windows 7, probablemente perderá esa conexión (recibirá una notificación que indica que Windows no pudo volver a conectar algunas de las unidades de red). Si tiene una aplicación que requiere acceso a los archivos de ese servidor e intenta acceder a ella sin proporcionar sus credenciales, obtendrá excepciones de acceso denegado. Si realiza una llamada exitosa a WNetAddConnection2, no solo reparará su unidad de red no asignada, sino que también podrá acceder a los archivos/directorios a través del espacio de nombres System.IO.
Usamos Sharepoint y esto funcionó para mí. Gracias a los otros chicos por responder también.
Respondido el 13 de junio de 12 a las 21:06
No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas vb.net authentication sharepoint unc or haz tu propia pregunta.
posible duplicado de Mover el archivo al recurso compartido de red (mediante suplantación) C # - Cᴏʀʏ
Un recurso adicional de MSDN: msdn.microsoft.com/en-us/library/chf6fbt4.aspx. Al darse cuenta de que ya ha intentado esto (# 1 en su publicación), es posible que deba mostrar algún código para diagnosticar por qué está obteniendo excepciones. - Cᴏʀʏ
Código agregado a la publicación anterior: test
El código en el otros post y el ejemplo de MSDN son ligeramente diferentes y más complicados de lo que ha intentado. Dales una oportunidad a ambos e informa. - Cᴏʀʏ
Los probé y no funcionan. Todavía obtengo un error de acceso denegado. Piensa que uno de nosotros no está entendiendo algo. No debería tener que suplantarme para acceder al servidor, ya estoy conectado como el usuario que quiero acceder a los archivos. Debe haber algo que me estoy perdiendo. - test