从系列之中的上一篇文章,我介绍了如何支持Windows Live ID来登录自己的网站,这一篇按照顺序,我介绍如何支持使用Yahoo BBAuth来登录网站,和上面的一篇文章一样,我将会仅仅对具体的逻辑进行实现,不再重复基础的原理。
关于Yahoo BBAuth的更多信息,请参考:Browser-Based Authentication。
可以先看Yahoo提供的BBAuth的原理示意图:
![](http://us.i1.yimg.com/us.yimg.com/i/ydn/bbauth.png)
第一步当然也是到Yahoo! Developer Network Home去注册你的程序,注册界面大致是这样的:
![](https://www.cnblogs.com/images/cnblogs_com/step1/yahoo_bbauth_reg.gif)
在注册完成之后,就可以在My Projects之中看到如下的应用程序信息:
![](https://www.cnblogs.com/images/cnblogs_com/step1/yahoo_bbauth_list.gif)
当然,Shared Secret需要点击链接才能看到,这里不得不要批评一下BBAuth的是,所有的信息注册之后没有看到什么地方可以修改,要改动一个什么(例如底下的访问数据列表),都需要重新注册一个应用程序,这样的设计似乎有点奇怪,还有一点,就是Yahoo提供的文档虽然不怎么样(我曾经因为一个时间格式问题被折磨了好久),各个范例和源码其实是很多的,只是不太好找,可能是我的英文功底不够吧。
好,闲话少说,在经过注册之后,得到了这样几个参数:appid,secret,这几个参数在程序之中需要使用的。
先看如何得到用来让用户登录的转向地址,这个非常容易,那几个参数也是现成的,只是格式是严格要求的,一定不能出错,否则反正Yahoo的BBAuth服务器反正就是给你出个错,让你摸不着头脑了,详细的代码还是在下面看看代码吧。
得到转向地址并转向给Yahoo之后,就可以将用户转向到Yahoo的公共登录界面,用户登录之后,就会出现关于登录许可的提示,用户只有点击同意才能继续登录的过程。
![](https://www.cnblogs.com/images/cnblogs_com/step1/yahoo_bbauth_confirm.gif)
登录完成之后,就开始Yahoo的服务器的就开始回转到你的Web应用程序,回传之后,根据请求的参数,需要按顺序完成以下步骤:
1.检查回传得Token是否正常;
2.根据回传的Token向Yahoo的服务器请求WSSID;
3.根据WSSID向Ymail接口请求用户的E-mail地址;
得到E-mail地址之后,就完成了整个登录过程。
下面是实现过程的代码:
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
BBAuthServer.cs代码
1
public class BBAuthServer:BaseServer
2![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
3
private string appid, secret, server, pathLogin, pathPwtoken_login;
4
private int timeout=300;
5
//采用Web.Config之中的XML节点作为构造函数参数
6
public BBAuthServer(System.Xml.XmlNode node)
7
: base(node)
8![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
9
for (int i = 0; i < node.Attributes.Count; i++)
10![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
11
switch (node.Attributes[i].LocalName)
12![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
13
case "appid":
14
appid = node.Attributes[i].Value;
15
break;
16
case "secret":
17
secret = node.Attributes[i].Value;
18
break;
19
case "server":
20
server = node.Attributes[i].Value;
21
break;
22
case "pathLogin":
23
pathLogin = node.Attributes[i].Value;
24
break;
25
case "pathPwtoken_login":
26
pathPwtoken_login = node.Attributes[i].Value;
27
break;
28
case "timeout":
29
timeout = int.Parse(node.Attributes[i].Value);
30
break;
31
}
32
}
33
}
34
public bool checkRequest(HttpRequest Request)
35![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
36
string ts = Request["ts"];
37
string sig = Request["sig"];
38
//先检查时间
39
if (Math.Abs(long.Parse(ts) - ((long)((DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds))) > timeout)
40![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
41
// throw new Exception("Error parsing timeout.");
42
}
43
//再检查签名
44
string baseString = System.Text.RegularExpressions.Regex.Replace(Request.Url.PathAndQuery, "&sig=[^&]+", "");
45
if (System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(baseString + secret, "MD5").ToLower() != sig)
46![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
47
throw new Exception("Signature mismatch:" + baseString);
48
}
49
return true;
50
}
51
public string getWSSID(string token,out string cookie)
52![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
53
string ts = ((long)((DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds)).ToString();
54
string baseString = pathPwtoken_login+"appid=" + HttpUtility.UrlEncode(appid) + "&token=" + HttpUtility.UrlEncode(token) + "&ts=" + ts + "";
55
string sig = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(baseString + secret, "MD5").ToLower();
56
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(new Uri(server + baseString + "&sig=" + sig));
57
request.Method = "GET";
58
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
59
XmlDocument doc = new XmlDocument();
60
doc.Load(response.GetResponseStream());
61
cookie = doc.SelectSingleNode("//*[local-name()='Cookie']").InnerText.Trim().Substring(2);
62
return doc.SelectSingleNode("//*[local-name()='WSSID']").InnerText.Trim();
63
}
64
public string getUserName(string token,string wssid,string cookie)
65![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
66
try
67![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
68
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(new Uri("http://mail.yahooapis.com/ws/mail/v1.1/soap?appid=" + HttpUtility.UrlEncode(appid) + "&WSSID=" + HttpUtility.UrlEncode(wssid)));
69
request.Method = "POST";
70
request.CookieContainer = new System.Net.CookieContainer();
71
CookieCollection collection = new CookieCollection();
72
request.CookieContainer.Add(new Uri("http://mail.yahooapis.com/"), new Cookie("Y", cookie));
73
byte[] bytes = Encoding.UTF8.GetBytes("<?xml version=\"1.0\" encoding=\"utf-8\"?><SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/1999/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/1999/XMLSchema\" SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"><SOAP-ENV:Body><GetUserData xmlns=\"urn:yahoo:ymws\"></GetUserData></SOAP-ENV:Body></SOAP-ENV:Envelope>");
74
request.Headers.Add("SOAPAction", "\"\"");
75
request.ContentType = "application/soap+xml; charset=utf-8";
76
request.ContentLength = bytes.Length;
77
Stream rs = request.GetRequestStream();
78
rs.Write(bytes, 0, bytes.Length);
79
rs.Close();
80
HttpWebResponse response = getResponse(request);
81
XmlDocument doc = new XmlDocument();
82
doc.Load(response.GetResponseStream());
83
return doc.SelectSingleNode("//*[local-name()='defaultID']").InnerText;
84![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//*
85
ymws ymwsInstance = new ymws();
86
ymwsInstance.Url = "http://mail.yahooapis.com/ws/mail/v1.1/soap?appid=" + appid + "&wssid=" + wssid;
87
ymwsInstance.CookieContainer = new System.Net.CookieContainer();
88
CookieCollection collection = new CookieCollection();
89
ymwsInstance.CookieContainer.Add(new Uri("http://mail.yahooapis.com/"), new Cookie("Y", cookie));
90
GetUserDataResponse userData = ymwsInstance.GetUserData(new GetUserData());
91
return userData.data.userSendPref.defaultID;*/
92
}
93
catch (Exception)
94![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
95
return wssid;
96
}
97
}
98
public override string getLoginUrl()//生成登录的URL
99![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
100
string ts = ((long)((DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds)).ToString();
101
string baseString = pathLogin+"appid=" + HttpUtility.UrlEncode(appid) + "&appdata=" + HttpUtility.UrlEncode(name) + "&send_userhash=1&ts=" + ts + "";
102
string sig = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(baseString + secret, "MD5").ToLower();
103
return server + baseString + "&sig=" + sig;
104
}
105
public override void parseHandle(HttpContext page)//处理回转请求
106![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
107
checkRequest(page.Request);//检查回传请求是不是合法
108
string cookie;
109
string wssid = getWSSID(page.Request["token"],out cookie);//先获取wssid
110
string name = getUserName(page.Request["token"], wssid, cookie);//通过wssid获取用户名
111
//检查完毕,开始获得用户的WSSID
112
AccountHelper.setUserInfo(page.Request["userhash"], name, this.name);
113
AccountHelper.returnOpener();
114
page.Response.End();
115
}
116
public static HttpWebResponse getResponse(HttpWebRequest request)
117![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
118
try
119![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
120
return (HttpWebResponse)request.GetResponse();
121
}
122
catch (WebException e)
123![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
124
HttpContext.Current.Response.Write(e.Message);
125
string result = new StreamReader(e.Response.GetResponseStream()).ReadToEnd();
126
HttpContext.Current.Response.Write(result);
127
HttpContext.Current.Response.End();
128
}
129
return null;
130
}
131
}