在前面的文章之中,我介绍了一下Step1帐户登录系统的基本编程架构,而在这篇文章,将直接贴出相关的源码,由于这次的开发比较仓促,代码存在很多不完善的地方,因此,适合仅仅用来作为如何实现的代码,而不是适合直接使用,废话少说,直接看代码:
首先是登录页面的代码,代码分为代码文件和页面文件两个部分:
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
Login.aspx代码文件
1
public partial class LoginPage : System.Web.UI.Page
2![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
3
public string url,returnUrl=null;
4
public System.Collections.Specialized.NameValueCollection userInfo=null;
5
protected void Page_Load(object sender, EventArgs e)
6![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
7
url = Request.QueryString["url"];//获得登录完成后回转的URL
8
if (url == null || url.Length <= 0)
9![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
10
if (Request.UrlReferrer != null)
11![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
12
url = Request.UrlReferrer.ToString();
13
}
14
}
15
userInfo=AccountHelper.getUserInfo();//获得当前已经登录的用户信息
16
if (userInfo != null && url != null && url.Length > 1)
17![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
18
returnUrl = AccountHelper.getReturnUrl(url);//如果已经登陆,则直接将回转地址显示在页面的连接上
19
}
20
BaseServer server = AccountHelper.getServerByName(Request["ass"]);//如果通过ass参数指定了登录的类型(用户已经点击图标登录)
21
if (server != null)
22![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
23
if (url != null && url.Length > 0)
24![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
25
AccountHelper.saveUrl(url);//将登录回转的地址记录到Cookie
26
}
27
Response.Redirect(server.getLoginUrl(),true);//转向到相应的登录页面
28
}
29
}
30
}
下面是登录页面的页面文件,实际上就是显示登录界面的HTML内容:
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
Login.aspx页面文件
1![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
<%
@ Page Language="C#" AutoEventWireup="true" Inherits="Step1.AccountServer.LoginPage"%><html>
2
<head>
3
<title>Step1.cn账户登录系统</title>
4
</head>
5
<body>
6
<table>
7
<tr><td class="icon">
8
<a href='?ass=live.com&url=<%=HttpUtility.UrlEncode(url, System.Text.Encoding.Default)%>'><img src="icons/live.gif"/></a>
9
</td><td class="icon">
10
<a href='?ass=google.com&url=<%=HttpUtility.UrlEncode(url, System.Text.Encoding.Default)%>'><img src="icons/google.gif" class="icon"/></a>
11
</td><td class="icon">
12
<a href='?ass=yahoo.com&url=<%=HttpUtility.UrlEncode(url, System.Text.Encoding.Default)%>'><img src="icons/yahoo.gif" class="icon"/></a>
13
</td><td class="icon">
14
<a href='?ass=xiaonei.com&url=<%=HttpUtility.UrlEncode(url, System.Text.Encoding.Default)%>'><img src="icons/xiaonei.gif" class="icon"/></a>
15
</td></tr>
16
<tr><td class="desc">
17
<b>Live</b>,<b>MSN</b>,<b>Hotmail</b>用户
18
</td><td class="desc">
19
<b>Google</b>,<b>Gmail</b>用户
20
</td><td class="desc">
21
<b>Yahoo</b>,<b>Flickr</b>用户
22
</td><td class="desc">
23
<b>校内网</b>用户(即将推出)
24
</td></tr>
25
</table>
26![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
<%
if(userInfo!=null){%>
27
<div class="user">
28
<b><%=userInfo["name"]%></b> ,您好!您已经使用 <%=userInfo["type"]%> 账号登录
29![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
<%
if(returnUrl!=null) {%><a href="<%=returnUrl %>">点击返回</a><%
} %>
30
</div>
31
<%}%>
32
<div class="notice">说明:</div>
33
</body>
34
</html>
上可以看出,服务端支持哪几种登录方式和登录界面完全没有关系,前台登录界面并不是自动生成的。
然后是注销的Logout.aspx代码,注销的代码因为没有界面,因此没有页面文件(空文件),仅仅有一个代码文件:
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
Logout.aspx代码
1 public partial class LogoutPage : System.Web.UI.Page
2 {
3 protected void Page_Load(object sender, EventArgs e)
4 {
5 //退出系统,如果URL不存在,则返回登录页
6 string url = Request.QueryString["url"];
7 if (url == null || url.Length <= 0)
8 {
9 url = Request.UrlReferrer.ToString();
10 }
11 AccountHelper.clearCookie();//清除用户的Cookie
12 AccountHelper.redirect(url);
13 }
14 }
注销的代码要简单得多,不过不是最简单的,最简单的是Handler.aspx,这个文件之所以简单是因为同样没有页面文件,再加上其中的代码文件所做的事情都已经调用其它的类来完成,因此只有一个非常简单的代码文件:
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
Handler.aspx代码文件
1
public partial class HandlePage : System.Web.UI.Page
2![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
{
3
protected void Page_Load(object sender, EventArgs e)
4![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
5
BaseServer server = AccountHelper.getServerByName(Request["ass"]);//根据ASS参数找到对应的服务器类型对象
6
server.parseHandle(this.Context);//由该对象来处理返回请求
7
}
8
});
在上面的三个aspx文件的代码之中,无一例外的调用了AccountHelper类,这个类包含一些重要的静态方法,内容如下:
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
AccountHelper.cs
1
public class AccountHelper
2![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
3
//清除Cookie
4
public static void clearCookie()
5![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
6
HttpCookie loginCookie = new HttpCookie(Configuration.Instance().cookieName);
7
loginCookie.Expires = DateTime.Now.AddYears(-10);
8
loginCookie.Domain = Configuration.Instance().cookieDomain;
9
loginCookie.HttpOnly = false;
10
HttpContext.Current.Response.Cookies.Add(loginCookie);
11
}
12
//将用户信息加入到Cookie
13
public static void setUserInfo(string account, string name, string type)
14![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
15
HttpCookie loginCookie = new HttpCookie(Configuration.Instance().cookieName);
16
loginCookie.Domain = Configuration.Instance().cookieDomain;
17
loginCookie.Values.Add("account", Convert.ToBase64String(Encoding.UTF8.GetBytes(account)));
18
loginCookie.Values.Add("name", Convert.ToBase64String(Encoding.UTF8.GetBytes(name)));
19
loginCookie.Values.Add("type", Convert.ToBase64String(Encoding.UTF8.GetBytes(type)));
20
loginCookie.Expires = DateTime.Now.AddYears(1);
21
HttpContext.Current.Response.Cookies.Add(loginCookie);
22
}
23
//从Cookie之中获取用户信息
24
public static NameValueCollection getUserInfo()
25![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
26
HttpCookie cookie = HttpContext.Current.Request.Cookies[Configuration.Instance().cookieName];
27
if (cookie != null)
28![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
29
NameValueCollection userInfo = new NameValueCollection();
30
foreach (string key in cookie.Values)
31![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
32
userInfo.Add(key,Encoding.UTF8.GetString(Convert.FromBase64String(cookie.Values[key])));
33
}
34
return userInfo.HasKeys()?userInfo:null;
35
}
36
return null;
37
}
38
//保存URL以便在完成后转向
39
public static void saveUrl(string url)
40![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
41
HttpCookie loginCookie = new HttpCookie(Configuration.Instance().cookieName + "_url");
42
loginCookie.Value = url;
43
loginCookie.Domain=Configuration.Instance().cookieDomain;
44
loginCookie.Expires = DateTime.Now.AddDays(1);
45
HttpContext.Current.Response.Cookies.Add(loginCookie);
46
}
47
//将用户的登录参数加入到URL并回转给Web应用
48
public static void returnOpener()
49![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
50
HttpCookie urlCookie = HttpContext.Current.Request.Cookies[Configuration.Instance().cookieName + "_url"];
51
string url = getReturnUrl(urlCookie == null ? "./" : urlCookie.Value);
52
urlCookie.Expires = DateTime.Now.AddYears(-10);
53
HttpContext.Current.Response.Cookies.Add(urlCookie);
54
redirect(url);
55
}
56
//根据已登陆用户信息和回转的基础URL地址得到回转的URL
57
public static string getReturnUrl(string url)
58![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
59
url += (url.IndexOf("?") > 0) ? "&" : "?";
60
System.Collections.Specialized.NameValueCollection userInfo = HttpContext.Current.Request.Cookies[Configuration.Instance().cookieName].Values;
61
string[] infoArr = new string[userInfo.AllKeys.Length];
62
userInfo.CopyTo(infoArr, 0);
63
url += Configuration.Instance().paramName + "=" + HttpContext.Current.Server.UrlEncode(string.Join(",", userInfo.AllKeys) + ";" + string.Join(",", infoArr));
64
return url;
65
}
66
//转向到指定URL,否则转向到登录页
67
public static void redirect(string url)
68![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
69
if (url == null || url.Length <= 0)
70![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
71
HttpContext.Current.Response.Redirect("Login.aspx");
72
}
73
else
74![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
75
HttpContext.Current.Response.Redirect(url);
76
}
77
}
78
//根据帐户类型的名称返回对应的帐户服务对象
79
public static BaseServer getServerByName(string name)
80![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
81![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (name == null || name.Length < 1)
{ return null; }
82
BaseServer[] servers=Configuration.Instance().AccountServers;
83
for (int i = 0; i < servers.Length; i++)
84![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
85
if (servers[i].name == name)
86![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
87
return servers[i];
88
}
89
}
90
return null;
91
}
92
public static string getHandleUrl()
93![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
94
return Configuration.Instance().rootUrl + "Handler.aspx";
95
}
96
public static string getLoginUrl()
97![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
98
return Configuration.Instance().rootUrl + "Login.aspx";
99
}
100
}
上面的代码就是比较长的一段了,不过确实是比较重要的一些方法,而下面的BaseServer.cs是一个抽象类,所有的登录类型(例如Google AuthSub类型,Yahoo BBAuth类型)都继承自此类,此类本身不能实例化:
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
BaseServer.cs
1
public abstract class BaseServer
2![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
3
public string name;
4
public BaseServer(System.Xml.XmlNode node)
5![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
6
for (int i = 0; i < node.Attributes.Count; i++)
7![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
8
switch (node.Attributes[i].LocalName)
9![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
10
case "name":
11
name = node.Attributes[i].Value;
12
break;
13
}
14
}
15
}
16
public virtual string getLoginUrl()
17![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
18
return "";
19
}
20
public virtual void parseHandle(HttpContext page)
21![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
22
}
23
public virtual string getHandleUrl()
24![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
25
return AccountHelper.getHandleUrl()+"?ass=" + name;
26
}
27
}
到这里,这些基础的类就都介绍完毕,我之所以不厌其烦的将这些代码都贴上来,主要是为后面介绍每一种登录类型的时候,能够比较清晰的看出是登录过程如何实现的,上面的代码都比较简单,因为都是本站自己的逻辑,但是当涉及到和Google、Yahoo等的帐户服务器交互的时候,很多时候必须完全按照对应的接口来做,因此会比较难懂。