What is the C# equivalent of this PHP cookie parsing snippet?
I'm trying to convert this PHP cookie parsing snippet into C#, but my PHP is a bit rusty. It's taken from a facebook SDK sample.
<?php
define('FACEBOOK_APP_ID', 'your application id');
define('FACEBOOK_SECRET', 'your application secret');
function get_facebook_cookie($app_id, $application_secret) {
$args = array();
parse_str(trim($_COOKIE['fbs_' . $app_id], '\\"'), $args);
ksort($args);
$payload = '';
foreach ($args as $key => $value) {
if ($key != 'sig') {
$payload .= $key . '=' . $value;
}
}
if (md5($payload . $application_secret) != $args['sig']) {
return null;
}
return $args;
}
$cookie = get_facebook_cookie(FACEBOOK_APP_ID, FACEBOOK_SECRET);
echo 'The ID of the current user is ' . $cookie['uid'];
?>
This is what I have so far, but its not quite right:
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
HttpCookie cookie = GetCookie();
IsLoggedIn = cookie != null;
}
private HttpCookie GetCookie()
{
// based on the php example at http://developers.fac开发者_JAVA百科ebook.com/docs/authentication/
HttpCookie cookie = Request.Cookies["fbs_" + FacebookClientId];
StringBuilder payload = new StringBuilder();
if (cookie != null)
{
foreach (string key in cookie.Values.Keys)
{
if (key != "sig")
{
payload.Append(key + "=" + cookie.Values[key]);
}
}
string sig = cookie.Values["sig"];
if (sig == GetMD5Hash(payload.ToString()))
{
return cookie;
}
}
return null;
}
public string GetMD5Hash(string input)
{
MD5CryptoServiceProvider cryptoServiceProvider = new MD5CryptoServiceProvider();
byte[] bytes = Encoding.UTF8.GetBytes(input);
bytes = cryptoServiceProvider.ComputeHash(bytes);
StringBuilder s = new StringBuilder();
foreach (byte b in bytes)
{
s.Append(b.ToString("x2").ToLower());
}
return s.ToString();
}
The one part I'm not sure about is parse_str(trim($_COOKIE['fbs_' . $app_id], '\\"'), $args);
. From what I can tell its creating an array out of the trimmed cookie value. Can anyone provide some assistance?
If I'm reading it correctly:
trim($_COOKIE['fbs_' . $app_id], '\\"')
Will trim \
and "
from the beginning and end of the value stored in the cookie named fbs_FACEBOOK_APP_ID
(The double back-slashes escape the back-slash in a single quoted string. And trim can be told what characters to trim from the string.)
Meanwhile, parse_str
then parses that as if it were a query string, into an associative array. So, I'd assume that the value of that cookie should look like a query string.
Hope this helps.
There were a few issues in my original C# version.
- I forgot to include the FacebookSecret as salt in the MD5 hash.
- The cookie.Value needs to be trimmed and parsed as a query string as George Marian and Alex JL explained.
- The parsed cookie values need to be UrlDecoded. I guess ASP.NET UrlEncodes them when creating the Cookie object.
- The default encoding should be used to create the hash, not UTF8.
Here's the working solution:
private HttpCookie GetCookie()
{
// based on the php example at http://developers.facebook.com/docs/guides/canvas/#canvas
HttpCookie cookie = Request.Cookies["fbs_" + FacebookClientId];
if (cookie != null)
{
var pairs = from pair in cookie.Value.Trim('"', '\\').Split('&')
let indexOfEquals = pair.IndexOf('=')
orderby pair
select new
{
Key = pair.Substring(0, indexOfEquals).Trim(),
Value = pair.Substring(indexOfEquals + 1).Trim()
};
IDictionary<string, string> cookieValues =
pairs.ToDictionary(pair => pair.Key, pair => Server.UrlDecode(pair.Value));
StringBuilder payload = new StringBuilder();
foreach (KeyValuePair<string, string> pair in cookieValues)
{
Response.Write(pair.Key + ": " + pair.Value + "<br/>\n");
if (pair.Key != "sig")
{
payload.Append(pair.Key + "=" + pair.Value);
}
}
string sig = cookieValues["sig"];
string hash = GetMd5Hash(payload + FacebookSecret);
if (sig == hash)
{
return cookie;
}
}
return null;
}
private static string GetMd5Hash(string input)
{
MD5CryptoServiceProvider cryptoServiceProvider = new MD5CryptoServiceProvider();
byte[] bytes = Encoding.Default.GetBytes(input);
byte[] hash = cryptoServiceProvider.ComputeHash(bytes);
StringBuilder s = new StringBuilder();
foreach (byte b in hash)
{
s.Append(b.ToString("x2"));
}
return s.ToString();
}
精彩评论