在前面的文章之中,我介绍了一下Step1帐户登录系统的基本编程架构,而在这篇文章,将直接贴出相关的源码,由于这次的开发比较仓促,代码存在很多不完善的地方,因此,适合仅仅用来作为如何实现的代码,而不是适合直接使用,废话少说,直接看代码:
首先是登录页面的代码,代码分为代码文件和页面文件两个部分:
Login.aspx代码文件
1 public partial class LoginPage : System.Web.UI.Page
2 {
3 public string url,returnUrl=null;
4 public System.Collections.Specialized.NameValueCollection userInfo=null;
5 protected void Page_Load(object sender, EventArgs e)
6 {
7 url = Request.QueryString["url"];//获得登录完成后回转的URL
8 if (url == null || url.Length <= 0)
9 {
10 if (Request.UrlReferrer != null)
11 {
12 url = Request.UrlReferrer.ToString();
13 }
14 }
15 userInfo=AccountHelper.getUserInfo();//获得当前已经登录的用户信息
16 if (userInfo != null && url != null && url.Length > 1)
17 {
18 returnUrl = AccountHelper.getReturnUrl(url);//如果已经登陆,则直接将回转地址显示在页面的连接上
19 }
20 BaseServer server = AccountHelper.getServerByName(Request["ass"]);//如果通过ass参数指定了登录的类型(用户已经点击图标登录)
21 if (server != null)
22 {
23 if (url != null && url.Length > 0)
24 {
25 AccountHelper.saveUrl(url);//将登录回转的地址记录到Cookie
26 }
27 Response.Redirect(server.getLoginUrl(),true);//转向到相应的登录页面
28 }
29 }
30 }
下面是登录页面的页面文件,实际上就是显示登录界面的HTML内容:
Login.aspx页面文件
1<%@ 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<% if(userInfo!=null){%>
27<div class="user">
28 <b><%=userInfo["name"]%></b> ,您好!您已经使用 <%=userInfo["type"]%> 账号登录
29 <%if(returnUrl!=null) {%><a href="<%=returnUrl %>">点击返回</a><%} %>
30</div>
31<%}%>
32<div class="notice">说明:</div>
33</body>
34</html>
上可以看出,服务端支持哪几种登录方式和登录界面完全没有关系,前台登录界面并不是自动生成的。
然后是注销的Logout.aspx代码,注销的代码因为没有界面,因此没有页面文件(空文件),仅仅有一个代码文件:
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,这个文件之所以简单是因为同样没有页面文件,再加上其中的代码文件所做的事情都已经调用其它的类来完成,因此只有一个非常简单的代码文件:
Handler.aspx代码文件
1public partial class HandlePage : System.Web.UI.Page
2{
3 protected void Page_Load(object sender, EventArgs e)
4 {
5 BaseServer server = AccountHelper.getServerByName(Request["ass"]);//根据ASS参数找到对应的服务器类型对象
6 server.parseHandle(this.Context);//由该对象来处理返回请求
7 }
8});
在上面的三个aspx文件的代码之中,无一例外的调用了AccountHelper类,这个类包含一些重要的静态方法,内容如下:
AccountHelper.cs
1 public class AccountHelper
2 {
3 //清除Cookie
4 public static void clearCookie()
5 {
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 {
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 {
26 HttpCookie cookie = HttpContext.Current.Request.Cookies[Configuration.Instance().cookieName];
27 if (cookie != null)
28 {
29 NameValueCollection userInfo = new NameValueCollection();
30 foreach (string key in cookie.Values)
31 {
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 {
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 {
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 {
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 {
69 if (url == null || url.Length <= 0)
70 {
71 HttpContext.Current.Response.Redirect("Login.aspx");
72 }
73 else
74 {
75 HttpContext.Current.Response.Redirect(url);
76 }
77 }
78 //根据帐户类型的名称返回对应的帐户服务对象
79 public static BaseServer getServerByName(string name)
80 {
81 if (name == null || name.Length < 1) { return null; }
82 BaseServer[] servers=Configuration.Instance().AccountServers;
83 for (int i = 0; i < servers.Length; i++)
84 {
85 if (servers[i].name == name)
86 {
87 return servers[i];
88 }
89 }
90 return null;
91 }
92 public static string getHandleUrl()
93 {
94 return Configuration.Instance().rootUrl + "Handler.aspx";
95 }
96 public static string getLoginUrl()
97 {
98 return Configuration.Instance().rootUrl + "Login.aspx";
99 }
100 }
上面的代码就是比较长的一段了,不过确实是比较重要的一些方法,而下面的BaseServer.cs是一个抽象类,所有的登录类型(例如Google AuthSub类型,Yahoo BBAuth类型)都继承自此类,此类本身不能实例化:
BaseServer.cs
1 public abstract class BaseServer
2 {
3 public string name;
4 public BaseServer(System.Xml.XmlNode node)
5 {
6 for (int i = 0; i < node.Attributes.Count; i++)
7 {
8 switch (node.Attributes[i].LocalName)
9 {
10 case "name":
11 name = node.Attributes[i].Value;
12 break;
13 }
14 }
15 }
16 public virtual string getLoginUrl()
17 {
18 return "";
19 }
20 public virtual void parseHandle(HttpContext page)
21 {
22 }
23 public virtual string getHandleUrl()
24 {
25 return AccountHelper.getHandleUrl()+"?ass=" + name;
26 }
27 }
到这里,这些基础的类就都介绍完毕,我之所以不厌其烦的将这些代码都贴上来,主要是为后面介绍每一种登录类型的时候,能够比较清晰的看出是登录过程如何实现的,上面的代码都比较简单,因为都是本站自己的逻辑,但是当涉及到和Google、Yahoo等的帐户服务器交互的时候,很多时候必须完全按照对应的接口来做,因此会比较难懂