问题
I am currently working on a project that requires using the Yammer API. The intent is to bypass using a browser, and use HttpWebRequest to do all authentication. Originally, this was working for me, but now I get a 404 error when I try to call GetResponse().
For my URL, I have tried using
https://www.yammer.com/session?client_id={CLIENT_ID}
as well as
https://www.yammer.com/session
using (var stream = webrequest.GetRequestStream())
{
stream.Write(postdata, 0, postdata.Length);
}
try
{
webresponse = webrequest.GetResponse() as HttpWebResponse;
}
catch (WebException ex)
{
webresponse = ex.Response as HttpWebResponse;
}
Have they changed the URL or am I doing something wrong?
回答1:
The following is my code snippet for yammer authentication. Steve Pescha's article - http://blogs.technet.com/b/speschka/archive/2013/10/05/using-the-yammer-api-in-a-net-client-application.aspx explains how to perform Programmatic yammer authentication. I have customized it according to my needs.
public class YammerSession
{
#region Variables
/// <summary>
/// The client identifier
/// </summary>
private readonly string clientId = "XXXXXXXX";
/// <summary>
/// client secret
/// </summary>
private readonly string clientSecret = "XXXXXXXX";
/// <summary>
/// Cookie container that stores yammer authentication information
/// </summary>
private CookieContainer cookieContainer = new CookieContainer(2);
/// <summary>
/// The user code sent in response to login request
/// </summary>
private string userCode;
/// <summary>
/// The user email
/// </summary>
private string email;
/// <summary>
/// The user password
/// </summary>
private SecureString password;
#endregion
#region Methods
/// <summary>
/// Gets the supported yammer version
/// </summary>
public static int SupportedVersion
{
get
{
return 1;
}
}
/// <summary>
/// Gets the client id.
/// </summary>
public string ClientId
{
get
{
return this.clientId;
}
}
/// <summary>
/// Gets the authenticity token.
/// </summary>
/// <value>
/// The authenticity token.
/// </value>
public string AuthenticityToken { get; private set; }
/// <summary>
/// Gets the token.
/// </summary>
/// <value>
/// The token.
/// </value>
public string Token { get; private set; }
/// <summary>
/// Connects the specified connection.
/// </summary>
public override void Connect()
{
this.InternalLogin(this.Connection.User, this.Connection.Password);
}
/// <summary>
/// Disconnects this instance.
/// </summary>
public override void Disconnect()
{
// Log out
this.InternalLogout(this.Connection.Address);
}
/// <summary>
/// Creates the web request to a service endpoint.
/// </summary>
/// <param name="serviceEndpoint">The service endpoint.</param>
/// <returns>
/// A new HTTP web request.
/// </returns>
public string GetEndpoint(string serviceEndpoint)
{
// Get the uri
var requestUri = string.Format("{0}/api/v{1}/{2}", this.Connection.Address, SupportedVersion, serviceEndpoint);
// return the result
return requestUri;
}
/// <summary>
/// Connects the specified email.
/// </summary>
/// <param name="email">The email.</param>
/// <param name="password">The password.</param>
private void InternalLogin(string email, SecureString password)
{
this.email = email;
this.password = password;
// Get the user code.
this.GetUserCode();
// Now get the bearer token
this.GetBearerToken(this.userCode);
}
/// <summary>
/// Gets the user code.
/// </summary>
private void GetUserCode()
{
string yammerAuthUrl = string.Format("https://www.yammer.com/dialog/oauth?client_id={0}", this.clientId);
string yammerSessionUrl = string.Format("https://www.yammer.com/session?client_id={0}", this.clientId);
// The authenticity token
string authenticityToken = string.Empty;
// Make a get request to Yammer authentication endpoint and get the response
using (HttpWebResponse webResponse = this.MakeGetRequestToEndPoint(yammerAuthUrl))
{
// Set the cookies
this.SetCookies(webResponse);
// Look for authenticity token
authenticityToken = this.GetAuthenticityToken(SessionHelper.ConvertResponseStreamToString(webResponse, Encoding.UTF8));
}
if (!string.IsNullOrEmpty(authenticityToken))
{
// Construct the post body with user login information
string postBody = string.Format(
"{0}{1}{2}{3}{4}{5}{6}",
"utf8=%E2%9C%93&authenticity_token=",
HttpUtility.UrlEncode(authenticityToken),
"&network_permalink=&login=",
HttpUtility.UrlEncode(this.email),
"&password=",
HttpUtility.UrlEncode(this.password.ConvertToUnsecureString()),
"&remember_me=off");
// Make the first post for User Code
HttpWebResponse sessionPostWebResponse = this.MakePostRequestToEndPoint(postBody, yammerSessionUrl);
string postResults = this.GetResponseAsString(sessionPostWebResponse);
// Get the next auth token that was returned. This will be used for logout purposes
this.AuthenticityToken = this.GetAuthenticityToken(postResults);
using (HttpWebResponse webResponse = this.MakeGetRequestToEndPoint(yammerAuthUrl, true))
{
// Now look for the query string and set the user code
this.userCode = webResponse.ResponseUri.Query;
// Check whether we are in Authorization Page
if (this.userCode.IndexOf("?client_id") >= 0)
{
// Construct the yammer network name
string yammerNetworkName = webResponse.ResponseUri.AbsolutePath.Substring(0, webResponse.ResponseUri.AbsolutePath.ToLower().IndexOf("dialog/"));
// Construct the yammer decision url
string yammerUserAuthDecisionUrl = string.Format(
"{0}{1}{2}{3}{4}",
"https://www.yammer.com",
yammerNetworkName,
"oauth2/decision?client_id=",
this.clientId,
"&redirect_uri=https%3A%2F%2Fwww.yammer.com&response_type=code");
// Construct the Payload for authorization page
string payLoad = "utf8=%E2%9C%93&authenticity_token=" + HttpUtility.UrlEncode(this.AuthenticityToken) + "&allow=Allow";
// Authorize the app by posting the request
using (HttpWebResponse decisionPostWebResponse = this.MakePostRequestToEndPoint(payLoad, yammerUserAuthDecisionUrl))
{
// Reset the user Code
this.userCode = decisionPostWebResponse.ResponseUri.Query;
}
}
// App should have been granted access at this point if it did not already have access.
// Now check whether the code is present in the query string
if (this.userCode.IndexOf("?code=") < 0)
{
throw new ArgumentException(Properties.ErrorMessges.UnableToLogin);
}
this.userCode = this.userCode.Replace("?code=", string.Empty);
}
}
}
/// <summary>
/// Get Yammer Authenticity Token
/// </summary>
/// <param name="rawHtml">The Yammer response that was got after posting to yammer endpoint</param>
/// <returns>The Yammer authenticity token</returns>
private string GetAuthenticityToken(string rawHtml)
{
string result = string.Empty;
int at = rawHtml.IndexOf("<meta name=\"authenticity_token\" id=\"authenticity_token\"");
if (at > -1)
{
// Get the authenticity token string
int et = rawHtml.IndexOf("/>", at + 1);
string tokenText = rawHtml.Substring(at, et - at);
// Get the token value
int ts = tokenText.IndexOf("content=");
int es = tokenText.LastIndexOf("\"");
result = tokenText.Substring(ts + 9, es - ts - 9);
}
return result;
}
/// <summary>
/// Perform a get request to an endpoint and return the Http response
/// </summary>
/// <param name="endPoint">The endpoint to make the request</param>
/// <param name="addCookies">Should cookies be added to the request</param>
/// <returns>The Http Web Response</returns>
private HttpWebResponse MakeGetRequestToEndPoint(string endPoint, bool addCookies = false)
{
HttpWebRequest webRequest = WebRequest.CreateHttp(endPoint);
webRequest.Method = "GET";
if (addCookies)
{
webRequest.CookieContainer = this.cookieContainer;
}
return (HttpWebResponse)webRequest.GetResponse();
}
/// <summary>
/// Read the cookies from the web response object and store it in the cookie container instance variable
/// </summary>
/// <param name="webResponse">The Web Response object</param>
private void SetCookies(HttpWebResponse webResponse)
{
const string YAMTRAK_COOKIE = "yamtrak_id";
const string SESSION_COOKIE = "_workfeed_session_id";
const string LOGIN_CSRF_TOKEN_COOKIE = "login_csrf_token";
string cookies = webResponse.Headers["Set-Cookie"];
if (string.IsNullOrEmpty(cookies))
{
this.cookieContainer = new CookieContainer();
}
else
{
// Split the cookie based on , and ;
string[] sepChar = new string[2];
sepChar[0] = ",";
sepChar[1] = ";";
string[] cookieArray = cookies.Split(sepChar, StringSplitOptions.None);
// Declare variables to hold the different types of cookies
string login_csrf_token = string.Empty;
string yammerTrakToken = string.Empty;
string sessionToken = string.Empty;
// Parse the cookie array and store the cookies in the array
for (int i = 0; i < cookieArray.Length; i++)
{
if (cookieArray[i].IndexOf(YAMTRAK_COOKIE) >= 0)
{
yammerTrakToken = cookieArray[i];
}
if (cookieArray[i].IndexOf(SESSION_COOKIE) >= 0)
{
sessionToken = cookieArray[i];
}
if (cookieArray[i].IndexOf(LOGIN_CSRF_TOKEN_COOKIE) >= 0)
{
login_csrf_token = cookieArray[i];
}
}
// Create the cookie container
this.cookieContainer = new CookieContainer();
// Get the value for each of the cookie and add it to the cookie container
if (!string.IsNullOrWhiteSpace(yammerTrakToken))
{
yammerTrakToken = yammerTrakToken.Substring(YAMTRAK_COOKIE.Length + 1);
this.cookieContainer.Add(new Cookie(YAMTRAK_COOKIE, yammerTrakToken, "/", "www.yammer.com"));
}
if (!string.IsNullOrWhiteSpace(sessionToken))
{
sessionToken = sessionToken.Substring(SESSION_COOKIE.Length + 1);
this.cookieContainer.Add(new Cookie(SESSION_COOKIE, sessionToken, "/", "www.yammer.com"));
}
if (!string.IsNullOrWhiteSpace(login_csrf_token))
{
login_csrf_token = login_csrf_token.Substring(LOGIN_CSRF_TOKEN_COOKIE.Length + 1);
this.cookieContainer.Add(new Cookie(LOGIN_CSRF_TOKEN_COOKIE, login_csrf_token, "/", "www.yammer.com"));
}
}
}
/// <summary>
/// Make a post request to an endpoint and return the result
/// </summary>
/// <param name="postBody">The post request payload</param>
/// <param name="endPoint">The endpoint</param>
/// <returns>The response got from the server</returns>
private HttpWebResponse MakePostRequestToEndPoint(string postBody, string endPoint)
{
string responseString = string.Empty;
HttpWebRequest webRequest = WebRequest.CreateHttp(endPoint);
webRequest.Method = "POST";
webRequest.CookieContainer = this.cookieContainer;
webRequest.ContentType = "application/x-www-form-urlencoded";
SessionHelper.WritePayLoadToWebRequest(webRequest, postBody);
HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse();
return webResponse;
}
/// <summary>
/// Get Response as string
/// </summary>
/// <param name="webResponse">The http web response object</param>
/// <returns>The web response string</returns>
/// <remarks>The Http Response object would be disposed after use</remarks>
private string GetResponseAsString(HttpWebResponse webResponse)
{
string responseString = string.Empty;
using (webResponse)
{
responseString = SessionHelper.ConvertResponseStreamToString(webResponse, Encoding.UTF8);
}
return responseString;
}
/// <summary>
/// Gets the user code.
/// </summary>
/// <param name="userCode">The user code.</param>
/// <exception cref="System.TimeoutException">Waiting for login page load.
/// or
/// Waiting for post login page load.</exception>
private void GetBearerToken(string userCode)
{
string formatUri = string.Format("https://www.yammer.com/oauth2/access_token.json?client_id={0}&client_secret={1}&code={2}", this.clientId, this.clientSecret, userCode);
Uri yammerUri = new Uri(formatUri);
WebRequest webRequest = WebRequest.Create(yammerUri);
webRequest.Method = "GET";
using (WebResponse response = webRequest.GetResponse())
{
using (Stream responseStream = response.GetResponseStream())
{
DataContractJsonSerializer seralizer = new DataContractJsonSerializer(typeof(Model.JSON.Yammer.AccessTokenResponse));
Model.JSON.Yammer.AccessTokenResponse accessTokenResponse = (Model.JSON.Yammer.AccessTokenResponse)seralizer.ReadObject(responseStream);
if (string.IsNullOrWhiteSpace(accessTokenResponse.access_token.token))
{
throw new InvalidOperationException("Unable to extract Yammer.com authorization bearer token.");
}
// Set the bearer token
this.Token = accessTokenResponse.access_token.token;
}
}
}
/// <summary>
/// Internal logout.
/// </summary>
/// <param name="address">The address.</param>
private void InternalLogout(string address)
{
string formatUri = string.Format("{0}/logout?from=nav", address);
Uri yammerUri = new Uri(formatUri);
// Create request
var request = HttpWebRequest.CreateHttp(yammerUri);
// POST
request.Method = "POST";
// Set the cookie container
request.CookieContainer = this.cookieContainer;
// Sent the request body
request.ContentType = "application/x-www-form-urlencoded";
string requestBody = string.Format(
"authenticity_token={0}&_method=delete",
HttpUtility.UrlEncode(this.AuthenticityToken));
byte[] requestBodyUTF8 = Encoding.UTF8.GetBytes(requestBody);
// Set the length before writing the request steam.
request.ContentLength = requestBody.Length;
// Write the request stream
using (var requestStream = request.GetRequestStream())
{
using (StreamWriter streamWrite = new StreamWriter(requestStream))
{
streamWrite.Write(requestBody);
}
}
// Make the request
using (var response = request.GetResponse())
{
// Always read the response
using (Stream responseStream = response.GetResponseStream())
{
}
}
}
#endregion
}
In the above code replace your client Id, client secret, email and password. Then you can use the connect method to get the bearer token and disconnect to log out of yammer. Recently yammer changed the number of cookies that were passed back and forth and I have fixed the issue
来源:https://stackoverflow.com/questions/25389113/yammer-authentication-with-httpwebrequest