在上一篇文章之中,我具体的讲解了使用Google的Authsub接口来让自己的网站支持Google帐号登陆,今天要讲到的是Windows Live ID,即使用MSN或Hotmail的帐号来登录网站,因为其中的基础原理类似,因此,假如对登录的流程和原理不清楚的话,建议去看看我前面的几篇文章,在这里,我主要讲解具体的实现和源码。
关于Windows Live ID接口的更多信息,建议去参考查看Windows Live ID接口介绍网站的更多内容,我在这篇文章之中,仅仅会讲到Windows Live ID在Web Authentication上的一个应用。
首先,和Google AuthSub一样,你必须先在Live的云计算开发中心Azure Services Developer Portal去注册你的程序,其实几个星期前我注册程序的时候应该还不叫这个比较时髦的名字的,今天我因为写这个文章再上去一看,居然变成“云”了,这么说来,我已经“云计算”了一把了,呵呵!
现在的注册界面如图(我这里截图是修改界面,添加界面和这个类似):
![](https://www.cnblogs.com/images/cnblogs_com/step1/live_editProject.gif)
注册完成之后,就可以得到一个上面的Application ID,需要说明的是,上面的Return URL意义不是很大,可能仅仅在缺省的时候使用,因为我注册时候采用的图上显示的值,而实际上使用的却是http://account.step1.cn/account/Handler.aspx?ass=live.com,只要将这个值传递过去,Live ID服务应该就不使用注册的值了。
注册完成之后,就可以开始进行开发,需要说明的是,在Live ID站点上提供了一个非常简单的类WindowsLiveLogin.cs,应该可以在这个例子之中得到这个类:Running the C# QuickStart Sample,而且可能是因为有了这个类,Microsoft觉得不需要再去提供什么和服务端交互的文档了(反正我没有找到),因此,我就直接不改动任何程序的情况下使用了这个类,这样,一切就方便了很多了。
先看如何得到用来让用户登录的转向地址,这个太容易了,因为这正是WindowsLiveLogin类的方法,需要说明的是,WindowsLiveLogin类有几个方法来获得转向地址的,其中GetLoginUrl方法得到的地址仅仅进行用户登录,而不向用户申请任何权限,而GetConsentUrl(string scope)方法可以指定向用户申请读取相应数据的权限,和Google AuthSub一样,我们在使用Live的登录的时候也需要读取用户的地址本信息来获得用户的登录帐号地址,因此,我们使用wll.GetConsentUrl("Contacts.View");方法来获得转向URL,("Contacts.View"代表对地址本的只读访问),当然在使用这个方法之前,要先设置好PolicyUrl属性(隐私申明地址)和ReturnUrl属性(登录完成之后的回转地址);
有一点需要特别说明的是:在使用GetLoginUrl或者GetConsentUrl方法之前,Live要求用户必须必须已经指定WindowsLiveLogin的PolicyUrl属性,也就是隐私申明的地址,而且,要求指定的网址必须是能够访问的,似乎Live还会去检查这个网址是否能够访问的,我在系统之中将隐私申明的网址指定为我的登录页面,因为在那个页面有我关于保护用户隐私的申明。
将用户转向到刚才获取的URL之后,用户就会被转向到Live ID的登录页:
![](https://www.cnblogs.com/images/cnblogs_com/step1/live_login.gif)
用户输入自己的帐号登录之后,就会出现用户的授权提示信息,可惜因为我的测试帐号早就授权过了,所以,这个页面被直接跳过,我不能在这里给出截图,实在抱歉,在用户在授权信息页面上点击同意之后,Live就会转向到上面通过ReturnUrl指定的登录回转地址。
Live转回到登录回转地址的时候,会有多种参数(delauth,login,logout,clearcookie),根据Live接口的要求,这些类型都应该实现,具体每个类型代表如下含义:
1.delauth,这个是我主要用到的类型,就是在用户登录并授与访问权限之后,回转的类型,注意,必须调用GetConsentUrl方法才会得到这种回转,从参数之中可以获取到ConsentToken参数,就是后面要用到的数据访问令牌。
2.login,这是调用GetLoginUrl方法之后回转的类型,也就是说,是不需要访问用户的任何数据的情况下回转访问的参数类型;
3.logout,注销
4.clearcookie,清除Cookie
在本系统之中,仅仅使用了delauth,从参数之中获得ConsentToken参数,然后,我们可以使用这个数据令牌去获取用户的帐户名称和昵称,同样,也是访问Windows Live Contacts接口,因为Windows Live Contacts接口不是我要讲的主题,因此不做详细的介绍,需要了解我如何使用,参考我的代码即可。
取得用户的登录ID和昵称之后,写入到用户的Cookie之中,然后登录回转,采用Live登录的过程就算完成了,还有什么不清楚的地方的话,请参考我下面贴出的整体代码:
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
LiveServer.cs代码
1
public class LiveServer : BaseServer
2![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
3
public WindowsLiveLogin wll;
4
//采用Web.Config之中的XML节点作为构造函数参数
5
public LiveServer(System.Xml.XmlNode node):base(node)
6![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
7
wll = new WindowsLiveLogin(false);
8
for (int i = 0; i < node.Attributes.Count; i++)
9![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
10
switch (node.Attributes[i].LocalName)
11![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
12
case "appid":
13
wll.AppId = node.Attributes[i].Value;
14
break;
15
case "secret":
16
wll.Secret = node.Attributes[i].Value;
17
break;
18
case "securityalgorithm":
19
wll.SecurityAlgorithm = node.Attributes[i].Value;
20
break;
21
}
22
}
23
}
24
//采用回传得到的令牌获取用户的信息
25
public XmlDocument getData(string token)
26![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
27
string lid = wll.ProcessConsentToken(token).LocationID;
28
//访问用户的地址本
29
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(new Uri("https://livecontacts.services.live.com/users/@L@" + lid + "/rest/LiveContacts/owner"));
30
request.Method = "GET";
31
request.Headers.Add("Authorization", "DelegatedToken dt=\"" + wll.ProcessConsentToken(token).DelegationToken + "\"");
32
HttpWebResponse response = getResponse(request);
33
XmlDocument doc = new XmlDocument();
34
if (response != null)
35![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
36
doc.Load(response.GetResponseStream());
37
}
38
return doc;
39
}
40
public static HttpWebResponse getResponse(HttpWebRequest request)
41![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
42
try
43![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
44
return (HttpWebResponse)request.GetResponse();
45
}
46
catch (WebException e)
47![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
48
HttpContext.Current.Response.Write(e.Message);
49
string result = new StreamReader(e.Response.GetResponseStream()).ReadToEnd();
50
HttpContext.Current.Response.Write(result);
51
HttpContext.Current.Response.End();
52
}
53
return null;
54
}
55
//得到用户的登录URL地址
56
public override string getLoginUrl()
57![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
58
wll.PolicyUrl = AccountHelper.getLoginUrl();
59
wll.ReturnUrl = getHandleUrl();
60
return wll.GetConsentUrl("Contacts.View");
61
//return wll.GetLoginUrl();
62
}
63
//处理登录回转信息
64
public override void parseHandle(HttpContext page)
65![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
66
string action = page.Request["action"];
67
switch (action)
68![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
69
case "delauth":
70
//获得用户地址本XML数据
71
XmlDocument doc = getData(page.Request["ConsentToken"]);
72
//获取用户帐号
73
XmlNode node = doc.SelectSingleNode("Owner/WindowsLiveID");
74
string account = node != null ? node.InnerText : "";
75
//获取用户的昵称
76
node = doc.SelectSingleNode("Owner/Profiles/Personal/DisplayName");
77
string name = node != null ? node.InnerText : "";
78
//设置用户信息到Cookie
79
AccountHelper.setUserInfo(account, name, this.name);
80
//回转
81
AccountHelper.returnOpener();
82
page.Response.End();
83
break;
84
case "login"://这是Live接口要求定义支持的类型,系统之中没有主动使用这种请求
85
WindowsLiveLogin.User user = wll.ProcessLogin(page.Request.Form);//从URL参数之中解析出用户的登录信息
86
AccountHelper.setUserInfo(user.Id, user.Id, this.name);//这里的user.ID实际上已经是用户的E-mail
87
AccountHelper.redirect(wll.GetConsentUrl("Contacts.View", user.Token));
88
page.Response.End();
89
break;
90
case "logout"://这是Live接口要求定义支持的类型,系统之中没有主动使用这种请求
91
AccountHelper.clearCookie();
92
AccountHelper.returnOpener();
93
page.Response.End();
94
break;
95
case "clearcookie"://这是Live接口要求定义支持的类型,系统之中没有主动使用这种请求
96
default:
97
AccountHelper.clearCookie();
98
string type;
99
byte[] content;
100
wll.GetClearCookieResponse(out type, out content);
101
page.Response.ContentType = type;
102
page.Response.OutputStream.Write(content, 0, content.Length);
103
page.Response.End();
104
break;
105![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
106
}
107
}
108
}