2010-07-15 11 views
12

la API REST de IBM RTC da un ejemplo de un script de shell para la autenticación con el servidor:C# - WebRequest HTTP POST con Cookie (puerto desde el guión rizo)

COOKIES=./cookies.txt 

USER=my_user 
PASSWORD=my_password 
HOST="https://myJazzServer:9092/jazz" 

curl -k -c $COOKIES "$HOST/authenticated/identity" 

curl -k -L -b $COOKIES -c $COOKIES -d j_username=$USER -d j_password=$PASSWORD "$HOST/authenticated/j_security_check" 

Esto funciona perfectamente, sin embargo necesito para autenticar con el servidor usando C#.

Hasta ahora tengo el siguiente, pero no está funcionando (no devuelve la página de autorización):

CookieContainer _cookie; 

    public string _RTC() 
    { 
     HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://myJazzServer.com:9092/jazz/authenticated/identity"); 
     if (_cookie == null) 
     { 
      _cookie = new CookieContainer(); 
     } 
     string a; 
     request.CookieContainer = _cookie; 
     using (var response = request.GetResponse()) 
     { 
      using (StreamReader sr = new StreamReader(response.GetResponseStream())) 
      { 
       a = sr.ReadToEnd(); 
      } 
     } 




     byte[] data = (new ASCIIEncoding()).GetBytes("j_username=myUser&j_password=MyPass"); 

     request = (HttpWebRequest)WebRequest.Create("https://myJazzServer.com:9092/jazz/authenticated/j_security_check"); 

     request.Method = "POST"; 
     request.ContentType = "text/html"; 
     request.ContentLength = data.Length; 
     request.CookieContainer = _cookie; 
     Stream reqStream = request.GetRequestStream(); 
     reqStream.Write(data,0,data.Length); 

     string b; 

     using (var response = request.GetResponse()) 
     { 
      using (var reader = new StreamReader(response.GetResponseStream())) 
      { 
       b = reader.ReadToEnd(); 
      } 
     } 
    } 
+0

¿Podría ser un poco más específico sobre lo que "no funciona"? ¿Recibes una excepción, no hay contenido en la respuesta, código de estado HTTP inesperado (por ejemplo, 404, 407, etc.) en la respuesta, etc.? – Nathan

+0

@ Nathan, está devolviendo una página de autorización fallida, no puedo dar detalles porque lo que devuelve es un bootstrapper ajax con un método llamado authFailed (o algo por el estilo), por lo que no puedo obtener los detalles reales. –

Respuesta

20

Yo sugeriría que pruebe lo siguiente:

public class WebClientEx : WebClient 
{ 
    private CookieContainer _cookieContainer = new CookieContainer(); 

    protected override WebRequest GetWebRequest(Uri address) 
    { 
     WebRequest request = base.GetWebRequest(address); 
     if (request is HttpWebRequest) 
     { 
      (request as HttpWebRequest).CookieContainer = _cookieContainer; 
     } 
     return request; 
    } 
} 

class Program 
{ 
    static void Main() 
    { 
     using (var client = new WebClientEx()) 
     { 
      var response1 = client.DownloadString("https://myJazzServer.com:9092/jazz/authenticated/identity"); 

      var data = new NameValueCollection 
      { 
       { "j_username", "myUser" }, 
       { "j_password", "MyPass" }, 
      }; 
      var response2 = client.UploadValues("https://myJazzServer.com:9092/jazz/authenticated/j_security_check", data); 
      Console.WriteLine(Encoding.Default.GetString(response2)); 
     } 
    } 
} 

también para simplificar la depuración se podría activar el rastreo poniendo esto en su app.config:

<configuration> 

    <system.diagnostics> 
    <sources> 
     <source name="System.Net.Sockets" tracemode="protocolonly"> 
     <listeners> 
      <add name="System.Net.Sockets" type="System.Diagnostics.TextWriterTraceListener" initializeData="network.log" /> 
     </listeners> 
     </source> 
    </sources> 

    <switches> 
     <add name="System.Net.Sockets" value="Verbose"/> 
    </switches> 

    <trace autoflush="true" /> 
    </system.diagnostics> 
</configuration> 

esto creará un archivo de registro detallado de la actividad de red que podría simplificar la depuración.

+0

Bueno, eso funcionó por primera vez, aparte de que tu oferta es aproximadamente 1000 veces más bonita que la mía, no estoy muy seguro de por qué funcionó y la mía no, pero está funcionando ahora y eso es lo que cuenta. Bounty inc en 22 horas :) ¡Muchas gracias! –

+0

si hay una "Set-Cookie" en respuesta, su implementación se perderá, lo que podría causar un error de autenticación. – PerlDev

+0

Solté este código en una pequeña aplicación en la que he estado trabajando y que busca recursos de un sitio web que necesita autenticación. Todo lo que tuve que cambiar fue la información enviada en el POST, y simplemente funciona. ¡Asombrado! Ahora necesito ir y descubrir cómo funciona, ¡ya que parece ser pura magia! –

2

Aquí es un método alternativo si desea utilizar HttpWebResponse/HttpWebRequest:

public static HttpWebResponse requestSecureDocument(HttpWebRequest _request, string _rtcServerURL, string _userName, string _password) 
{ 
    //FormBasedAuth Step1: Request the resource and clone the request to be used later 
    HttpWebRequest _requestClone = WebRequestExtensions.CloneRequest(_request, _request.RequestUri); 
    //(HttpWebRequest)WebRequest.Create(request.RequestUri); 

    //store the response in _docResponse variable 
    HttpWebResponse _docResponse = (HttpWebResponse)_request.GetResponse(); 

    //HttpStatusCode.OK indicates that the request succeeded and that the requested information is in the response. 
    if (_docResponse.StatusCode == HttpStatusCode.OK) 
    { 
     //X-com-ibm-team-repository-web-auth-msg header signifies form based authentication is being used 
     string _rtcAuthHeader = _docResponse.Headers["X-com-ibm-team-repository-web-auth-msg"]; 
     if (_rtcAuthHeader != null && _rtcAuthHeader.Equals("authrequired")) 
     { 
      _docResponse.GetResponseStream().Flush(); 
      _docResponse.Close(); 

      //Prepare form for authentication as _rtcAuthHeader = authrequired 
      HttpWebRequest _formPost = (HttpWebRequest)WebRequest.Create(_rtcServerURL + "/j_security_check"); 
      _formPost.Method = "POST"; 
      _formPost.Timeout = 30000; 
      _formPost.CookieContainer = _request.CookieContainer; 
      _formPost.Accept = "text/xml"; 
      _formPost.ContentType = "application/x-www-form-urlencoded"; 

      String _authString = "j_username=" + _userName + "&amp;j_password=" + _password; 
      //create authentication string 
      Byte[] _outBuffer = Encoding.UTF8.GetBytes(_authString); //store in byte buffer 
      _formPost.ContentLength = _outBuffer.Length; 
      Stream _str = _formPost.GetRequestStream(); 
      _str.Write(_outBuffer, 0, _outBuffer.Length); //update form 
      _str.Close(); 

      //FormBasedAuth Step2:submit the login form and get the response from the server 
      HttpWebResponse _formResponse = (HttpWebResponse)_formPost.GetResponse(); 

      _rtcAuthHeader = _formResponse.Headers["X-com-ibm-team-repository-web-auth-msg"]; 
      //check if authentication has failed 
      if (_rtcAuthHeader != null && _rtcAuthHeader.Equals("authfailed")) 
      { 
       //authentication failed. You can write code to handle the authentication failure. 
       //if (DEBUG) Console.WriteLine("Authentication Failure"); 
      } 
      else 
      { 
       //login successful 
       _formResponse.GetResponseStream().Flush(); 
       _formResponse.Close(); 
       //FormBasedAuth Step3: Resend the request for the protected resource. 
       //if (DEBUG) Console.WriteLine("&gt;&gt; Response " + request.RequestUri); 
       return (HttpWebResponse)_requestClone.GetResponse(); 
      } 
     } 
    } 
    //already authenticated return original response_docResponse 
    return _docResponse; 
} 

Puede llamar a esta función en el código -

string _serverURL = https://localhost:9443/ccm; 
string _resourceURL = "https://localhost:9443/ccm/rootservices"; 

string mediatype = "application/xml"; 
string username = "username";          
string password = "password"; 
try 
{ 
    CookieContainer _cookies = new CookieContainer();//create cookie container 
    HttpWebRequest documentGet = (HttpWebRequest)WebRequest.Create(_resourceURL); 
    documentGet.Method = "GET"; //method 
    documentGet.CookieContainer = _cookies; //set container for HttpWebRequest 
    documentGet.Accept = mediatype; 
    documentGet.Headers.Set("OSLC-Core-Version", "3.0"); //for RTC 3.0.1.2 
    documentGet.Timeout = 300000; 
    HttpWebResponse response = requestSecureDocument(documentGet, _serverURL, username, password); 

    if (response.StatusCode != HttpStatusCode.OK) 
    { 
     Console.WriteLine(" Error: " + response.StatusDescription); 
     response.Close(); 
    } 
} 
catch (Exception ex) 
{ 
} 

Puede leer más at my blog.