关键字:单点登录 跨域 跨域单点登录
源代码下载:http://download.csdn.net/source/1571879
单点登录(Single Sign On),简称为 SSO,是目前比较流行的企业业务整合的解决方案之一。SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。
asp.net跨域单点登录分为:
1、跨子域单点登录。如 blog.a.com 和 info.a.com 这2个站点同属一个主域.a.com,实现跨子域单点登录很简单,可以利用cookie,设置Domain为".a.com‘即可,这里就不再赘叙。
2、完成跨域单点登录。如 http://www.a.com/ http://www.b.com/ 这2个站点之间实现共享一个身份验证系统,只需在一处地方登录,下面主要谈下这种方式的实现方法。
asp.net 跨域单点登录实现原理:
当用户第一次访问web应用系统1的时候,因为还没有登录,会被引导到认证中心进行登录;根据用户提供的登录信息,认证系统进行身份效验,如果通过效验,返回给用户一个认证的凭据;用户再访问别的web应用的时候就会将这个Token带上,作为自己认证的凭据,应用系统接受到请求之后会把Token送到认证中心进行效验,检查Token的合法性。如果通过效验,用户就可以在不用再次登录的情况下访问应用系统2和应用系统3了。所有应用系统共享一个身份认证系统。认证系统的主要功能是将用户的登录信息和用户信息库相比较,对用户进行登录认证;认证成功后,认证系统应该生成统一的认证标志,返还给用户。另外,认证系统还应该对Token进行效验,判断其有效性。 所有应用系统能够识别和提取Token信息要实现SSO的功能,让用户只登录一次,就必须让应用系统能够识别已经登录过的用户。应用系统应该能对Token进行识别和提取,通过与认证系统的通讯,能自动判断当前用户是否登录过,从而完成单点登录的功能。
比如说,我现在有3个分站点和1个认证中心(总站)。当用户访问分站点的时候,分站点会发Token到验证中心进行验证。验证中心判断用户是否已经登录。如果未登录,则返回到验证中心登录入口进行登录,否之则返回Token验证到分站点,直接进入分站点。
如图所示:
上面是实现单点登录的原理图,下面介绍下如何用asp.net实现跨域单点登录:
一、新建网站 MasterSite,作为总站认证中心。配置web.config,采用form登录验证。 配置如下:
1.<authentication mode="Forms"> 2. <forms name=".AspxFormAuth" loginUrl="Default.aspx" defaultUrl="center.html" protection="All" path="/" timeout="120"> 3. </forms> 4.</authentication> 5.<authorization> 6. <!--拒绝所有匿名用户--> 7. <deny users="?"/> 8.</authorization>
添加Default.aspx页面,用来进行登录。代码如下:
HTML Code:
1.<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %> 2. 3.<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 4. 5.<html xmlns="http://www.w3.org/1999/xhtml" > 6.<head runat="server"> 7. <title>总站登录</title> 8.</head> 9.<body> 10. <form id="form1" runat="server"> 11. <div> 12. <asp:Login ID="Login1" runat="server" OnAuthenticate="Login1_Authenticate" UserName="test"> 13. </asp:Login> 14. </div> 15. </form> 16.</body> 17.</html>
Default.cs Code:
1.using System; 2.using System.Data; 3.using System.Configuration; 4.using System.Web; 5.using System.Web.Security; 6.using System.Web.UI; 7.using System.Web.UI.WebControls; 8.using System.Web.UI.WebControls.WebParts; 9.using System.Web.UI.HtmlControls; 10.using System.Text; 11. 12.public partial class _Default : System.Web.UI.Page 13.{ 14. protected void Page_Load(object sender, EventArgs e) 15. { 16. if (!IsPostBack) 17. { 18. SSORequest ssoRequest = new SSORequest(); 19. 20. 21. #region 验证 Post 过来的参数 22. //-------------------------------- 23. // 请求注销 24. if (!string.IsNullOrEmpty(Request["Logout"])) 25. { 26. Authentication.Logout(); 27. return; 28. } 29. //-------------------------------- 30. // 各独立站点标识 31. if (string.IsNullOrEmpty(Request["IASID"])) 32. { 33. return; 34. } 35. else 36. { 37. ssoRequest.IASID = Request["IASID"]; 38. } 39. 40. //-------------------------------- 41. // 时间戳 42. if (string.IsNullOrEmpty(Request["TimeStamp"])) 43. { 44. return; 45. } 46. else 47. { 48. ssoRequest.TimeStamp = Request["TimeStamp"]; 49. } 50. 51. //-------------------------------- 52. // 各独立站点的访问地址 53. if (string.IsNullOrEmpty(Request["AppUrl"])) 54. { 55. return; 56. } 57. else 58. { 59. ssoRequest.AppUrl = Request["AppUrl"]; 60. } 61. 62. //-------------------------------- 63. // 各独立站点的 Token 64. if (string.IsNullOrEmpty(Request["Authenticator"])) 65. { 66. return; 67. } 68. else 69. { 70. ssoRequest.Authenticator = Request["Authenticator"]; 71. } 72. 73. ViewState["SSORequest"] = ssoRequest; 74. 75. #endregion 76. 77. 78. //验证从分站发过来的Token 79. if (Authentication.ValidateAppToken(ssoRequest)) 80. { 81. string userAccount = null; 82. 83. // 验证用户之前是否登录过 84. //验证 EAC 认证中心的 Cookie,验证通过时获取用户登录账号 85. if (Authentication.ValidateEACCookie(out userAccount)) 86. { 87. ssoRequest.UserAccount = userAccount; 88. 89. //创建认证中心发往各分站的 Token 90. if (Authentication.CreateEACToken(ssoRequest)) 91. { 92. Post(ssoRequest); 93. } 94. } 95. else 96. { 97. return; 98. } 99. } 100. else 101. { 102. return; 103. } 104. } 105. } 106. 107. 108. //post请求 109. void Post(SSORequest ssoRequest) 110. { 111. PostService ps = new PostService(); 112. 113. ps.Url = ssoRequest.AppUrl; 114. 115. ps.Add("UserAccount", ssoRequest.UserAccount); 116. ps.Add("IASID", ssoRequest.IASID); 117. ps.Add("TimeStamp", ssoRequest.TimeStamp); 118. ps.Add("AppUrl", ssoRequest.AppUrl); 119. ps.Add("Authenticator", ssoRequest.Authenticator); 120. 121. ps.Post(); 122. } 123. 124. /// <summary> 125. /// 验证登录账号和密码是否正确 126. /// </summary> 127. /// <param name="userName">登录账号</param> 128. /// <param name="userPwd">登录密码</param> 129. /// <returns></returns> 130. private bool ValidateUserInfo(string userName, string userPwd) 131. { 132. //从数据库中读取,验证登录账号和密码 133. //略... 134. return true; 135. } 136. 137. protected void Login1_Authenticate(object sender, AuthenticateEventArgs e) 138. { 139. if (string.IsNullOrEmpty(Login1.UserName) || string.IsNullOrEmpty(Login1.Password)) 140. { 141. Page.RegisterClientScriptBlock("Add", "<mce:script lanuage=\"javascript\"><!-- 142.alert(‘用户名密码不能为空!‘); 143.// --></mce:script>"); 144. return; 145. } 146. else if (ValidateUserInfo(Login1.UserName, Login1.Password) == false) 147. { 148. Page.RegisterClientScriptBlock("Add", "<mce:script lanuage=\"javascript\"><!-- 149.alert(‘用户名密码错误!‘); 150.// --></mce:script>"); 151. return; 152. } 153. else 154. { 155. Session["CurrUserName"] = Login1.UserName; 156. Session.Timeout = 120; 157. 158. SSORequest ssoRequest = ViewState["SSORequest"] as SSORequest; 159. 160. // 如果不是从各分站 Post 过来的请求,则默认登录主站 161. if (ssoRequest == null) 162. { 163. FormsAuthentication.SetAuthCookie(Login1.UserName, false); 164. 165. ssoRequest = new SSORequest(); 166. //主站标识ID 167. ssoRequest.IASID = "00"; 168. ssoRequest.AppUrl = "SiteList.aspx"; 169. ssoRequest.TimeStamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm"); 170. ssoRequest.Authenticator = string.Empty; 171. 172. Response.Redirect("SiteList.aspx"); 173. } 174. ssoRequest.UserAccount = Login1.UserName; 175. 176. //创建Token 177. if (Authentication.CreateEACToken(ssoRequest)) 178. { 179. string expireTime = DateTime.Now.AddHours(3).ToString("yyyy-MM-dd HH:mm"); 180. 181. Authentication.CreatEACCookie(ssoRequest.UserAccount, ssoRequest.TimeStamp, expireTime); 182. 183. Post(ssoRequest); 184. } 185. 186. } 187. } 188. 189. 190.}
代码说明:验证分站post过来的Token请求,如果用户已经登录,则创建认证中心发往各分站的 Token验证,转向分站,否之则返回登录。若是直接登录主站则转向站点选择页面sitelist.aspx,选择你要登录的分站点。
如图:
二、新建站点1,代码如下:
HTML Code:
1.<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %> 2. 3.<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 4. 5.<html xmlns="http://www.w3.org/1999/xhtml" > 6.<head runat="server"> 7. <title> 站点一</title> 8.</head> 9.<body> 10. <form id="form1" runat="server"> 11. <div> 12. <br /> 13. <br /> 14. <asp:LinkButton ID="LinkButton1" runat="server" OnClick="LinkButton1_Click">返回主站</asp:LinkButton> 15. 16. <asp:LinkButton ID="LinkButton2" runat="server" OnClick="LinkButton2_Click">注销登录</asp:LinkButton></div> 17. </form> 18.</body> 19.</html>
Default.cs code:
1.using System; 2.using System.Data; 3.using System.Configuration; 4.using System.Web; 5.using System.Web.Security; 6.using System.Web.UI; 7.using System.Web.UI.WebControls; 8.using System.Web.UI.WebControls.WebParts; 9.using System.Web.UI.HtmlControls; 10.using System.Text; 11. 12.public partial class _Default : System.Web.UI.Page 13.{ 14. protected void Page_Load(object sender, EventArgs e) 15. { 16. if (!IsPostBack) 17. { 18. #region SSO 部分代码 19. SSORequest ssoRequest = new SSORequest(); 20. 21. if (string.IsNullOrEmpty(Request["IASID"])) 22. { 23. ssoRequest.IASID = "01"; 24. ssoRequest.TimeStamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm"); 25. ssoRequest.AppUrl = Request.Url.ToString(); 26. Authentication.CreateAppToken(ssoRequest); 27. 28. Post(ssoRequest); 29. } 30. else if (!string.IsNullOrEmpty(Request["IASID"]) 31. && !string.IsNullOrEmpty(Request["TimeStamp"]) 32. && !string.IsNullOrEmpty(Request["AppUrl"]) 33. && !string.IsNullOrEmpty(Request["UserAccount"]) 34. && !string.IsNullOrEmpty(Request["Authenticator"])) 35. { 36. ssoRequest.IASID = Request["IASID"]; 37. ssoRequest.TimeStamp = Request["TimeStamp"]; 38. ssoRequest.AppUrl = Request["AppUrl"]; 39. ssoRequest.UserAccount = Request["UserAccount"]; 40. ssoRequest.Authenticator = Request["Authenticator"]; 41. 42. if (Authentication.ValidateEACToken(ssoRequest)) 43. { 44. //从数据库中获取UserId 45. Session["CurrUserName"] = Request["UserAccount"]; 46. Session.Timeout = 120; 47. FormsAuthentication.SetAuthCookie(Request["UserAccount"], false); 48. Response.Write(string.Format("{0},您好!欢迎来到site1, >> 访问<a href="\" mce_href="\""http://localhost/Site2/Default.aspx\">site2</a>",ssoRequest.UserAccount)); 49. } 50. } 51. 52. ViewState["SSORequest"] = ssoRequest; 53. 54. #endregion 55. } 56. } 57. 58. void Post(SSORequest ssoRequest) 59. { 60. PostService ps = new PostService(); 61. //认证中心(主站)地址 62. string EACUrl = "http://localhost/MasterSite/Default.aspx"; 63. ps.Url = EACUrl; 64. //ps.Add("UserAccount", ssoRequest.UserAccount); 65. ps.Add("IASID", ssoRequest.IASID); 66. ps.Add("TimeStamp", ssoRequest.TimeStamp); 67. ps.Add("AppUrl", ssoRequest.AppUrl); 68. ps.Add("Authenticator", ssoRequest.Authenticator);70. ps.Post(); 71. } 72. 73. 74. //注销登录 75. protected void LinkButton2_Click(object sender, EventArgs e) 76. { 77. FormsAuthentication.SignOut(); 78. 79. SSORequest ssoRequest = new SSORequest(); 80. 81. ssoRequest.IASID = "01"; 82. ssoRequest.TimeStamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm"); 83. ssoRequest.AppUrl = Request.Url.ToString(); 84. 85. Authentication.CreateAppToken(ssoRequest); 86. 87. PostService ps = new PostService(); 88. 89. //认证中心(主站)地址 90. string EACUrl = "http://localhost/MasterSite/Default.aspx"; 91. ps.Url = EACUrl; 92. 93. ps.Add("IASID", ssoRequest.IASID); 94. ps.Add("TimeStamp", ssoRequest.TimeStamp); 95. ps.Add("AppUrl", ssoRequest.AppUrl); 96. ps.Add("Authenticator", ssoRequest.Authenticator); 97. 98. ps.Add("Logout", "true"); 99. 100. ps.Post(); 101. } 102. 103. //返回主站 104. protected void LinkButton1_Click(object sender, EventArgs e) 105. { 106. if (Session["CurrUserName"] != null) 107. { 108. Response.Redirect("http://localhost/MasterSite/SiteList.aspx"); 109. } 110. } 111.}
配置web.config
1.<authentication mode="Forms"> 2. <forms name=".AspxFormAuth" loginUrl="Default.aspx" defaultUrl="center.html" protection="All" path="/" timeout="60"> 3. </forms> 4. </authentication> 5. <authorization> 6. <!--拒绝所有匿名用户--> 7. <deny users="?"/> 8. </authorization>
三、同二一样,新建站点Site2,代码如下:
1.using System; 2.using System.Data; 3.using System.Configuration; 4.using System.Web; 5.using System.Web.Security; 6.using System.Web.UI; 7.using System.Web.UI.WebControls; 8.using System.Web.UI.WebControls.WebParts; 9.using System.Web.UI.HtmlControls; 10. 11.public partial class _Default : System.Web.UI.Page 12.{ 13. protected void Page_Load(object sender, EventArgs e) 14. { 15. if (!IsPostBack) 16. { 17. #region SSO 部分代码 18. SSORequest ssoRequest = new SSORequest(); 19. 20. if (string.IsNullOrEmpty(Request["IASID"])) 21. { 22. ssoRequest.IASID = "02"; 23. ssoRequest.TimeStamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm"); 24. ssoRequest.AppUrl = Request.Url.ToString(); 25. Authentication.CreateAppToken(ssoRequest); 26. 27. Post(ssoRequest); 28. } 29. else if (!string.IsNullOrEmpty(Request["IASID"]) 30. && !string.IsNullOrEmpty(Request["TimeStamp"]) 31. && !string.IsNullOrEmpty(Request["AppUrl"]) 32. && !string.IsNullOrEmpty(Request["UserAccount"]) 33. && !string.IsNullOrEmpty(Request["Authenticator"])) 34. { 35. ssoRequest.IASID = Request["IASID"]; 36. ssoRequest.TimeStamp = Request["TimeStamp"]; 37. ssoRequest.AppUrl = Request["AppUrl"]; 38. ssoRequest.UserAccount = Request["UserAccount"]; 39. ssoRequest.Authenticator = Request["Authenticator"]; 40. 41. if (Authentication.ValidateEACToken(ssoRequest)) 42. { 43. Session["CurrUserName"] = Request["UserAccount"]; 44. Session.Timeout = 120; 45. FormsAuthentication.SetAuthCookie(Request["UserAccount"], false); 46. Response.Write(string.Format("{0},您好!欢迎来到site2, >> 访问<a href="\" mce_href="\""http://localhost/Site1/Default.aspx\">site1</a>", ssoRequest.UserAccount)); 47. } 48. } 49. 50. ViewState["SSORequest"] = ssoRequest; 51. 52. #endregion 53. } 54. } 55. 56. void Post(SSORequest ssoRequest) 57. { 58. PostService ps = new PostService(); 59. //认证中心(主站)地址 60. string EACUrl = "http://localhost/MasterSite/Default.aspx"; 61. ps.Url = EACUrl; 62. //ps.Add("UserAccount", ssoRequest.UserAccount); 63. ps.Add("IASID", ssoRequest.IASID); 64. ps.Add("TimeStamp", ssoRequest.TimeStamp); 65. ps.Add("AppUrl", ssoRequest.AppUrl); 66. ps.Add("Authenticator", ssoRequest.Authenticator); 67. 68. ps.Post(); 69. } 70. 71. 72. //注销登录 73. protected void LinkButton2_Click(object sender, EventArgs e) 74. { 75. FormsAuthentication.SignOut(); 76. 77. SSORequest ssoRequest = new SSORequest(); 78. 79. ssoRequest.IASID = "02"; 80. ssoRequest.TimeStamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm"); 81. ssoRequest.AppUrl = Request.Url.ToString(); 82. 83. Authentication.CreateAppToken(ssoRequest); 84. 85. PostService ps = new PostService(); 86. 87. //认证中心(主站)地址 88. string EACUrl = "http://localhost/MasterSite/Default.aspx"; 89. ps.Url = EACUrl; 90. 91. ps.Add("IASID", ssoRequest.IASID); 92. ps.Add("TimeStamp", ssoRequest.TimeStamp); 93. ps.Add("AppUrl", ssoRequest.AppUrl); 94. ps.Add("Authenticator", ssoRequest.Authenticator); 95. 96. ps.Add("Logout", "true"); 97. 98. ps.Post(); 99. } 100. 101. //返回主站 102. protected void LinkButton1_Click(object sender, EventArgs e) 103. { 104. if (Session["CurrUserName"] != null) 105. { 106. Response.Redirect("http://localhost/MasterSite/SiteList.aspx"); 107. } 108. } 109.}
对于tokent请求,tokent验证,需要对它进行加密、解密。
其它代码:
Authentication.cs
1.using System; 2.using System.Data; 3.using System.Configuration; 4.using System.Web; 5.using System.Web.Security; 6.using System.Collections.Generic; 7.using System.Text; 8. 9./// <summary> 10./// 安全验证类 11./// </summary> 12.public class Authentication 13.{ 14. static readonly string cookieName = "EACToken"; 15. static readonly string hashSplitter = "|"; 16. 17. public Authentication() 18. { 19. } 20. 21. public static string GetAppKey(int appID) 22. { 23. //string cmdText = @"select * from "; 24. return string.Empty; 25. } 26. 27. public static string GetAppKey() 28. { 29. return "22362E7A9285DD53A0BBC2932F9733C505DC04EDBFE00D70"; 30. } 31. 32. public static string GetAppIV() 33. { 34. return "1E7FA9231E7FA923"; 35. } 36. 37. /// <summary> 38. /// 取得加密服务 39. /// </summary> 40. /// <returns></returns> 41. static CryptoService GetCryptoService() 42. { 43. string key = GetAppKey(); 44. string IV = GetAppIV(); 45. 46. CryptoService cs = new CryptoService(key, IV); 47. return cs; 48. } 49. 50. /// <summary> 51. /// 创建各分站发往认证中心的 Token 52. /// </summary> 53. /// <param name="ssoRequest"></param> 54. /// <returns></returns> 55. public static bool CreateAppToken(SSORequest ssoRequest) 56. { 57. string OriginalAuthenticator = ssoRequest.IASID + ssoRequest.TimeStamp + ssoRequest.AppUrl; 58. string AuthenticatorDigest = CryptoHelper.ComputeHashString(OriginalAuthenticator); 59. string sToEncrypt = OriginalAuthenticator + AuthenticatorDigest; 60. byte[] bToEncrypt = CryptoHelper.ConvertStringToByteArray(sToEncrypt); 61. 62. CryptoService cs = GetCryptoService(); 63. 64. byte[] encrypted; 65. 66. if (cs.Encrypt(bToEncrypt, out encrypted)) 67. { 68. ssoRequest.Authenticator = CryptoHelper.ToBase64String(encrypted); 69. 70. return true; 71. } 72. else 73. { 74. return false; 75. } 76. } 77. 78. 79. /// <summary> 80. /// 验证从各分站发送过来的 Token 81. /// </summary> 82. /// <param name="ssoRequest"></param> 83. /// <returns></returns> 84. public static bool ValidateAppToken(SSORequest ssoRequest) 85. { 86. string Authenticator = ssoRequest.Authenticator; 87. 88. string OriginalAuthenticator = ssoRequest.IASID + ssoRequest.TimeStamp + ssoRequest.AppUrl; 89. string AuthenticatorDigest = CryptoHelper.ComputeHashString(OriginalAuthenticator); 90. string sToEncrypt = OriginalAuthenticator + AuthenticatorDigest; 91. byte[] bToEncrypt = CryptoHelper.ConvertStringToByteArray(sToEncrypt); 92. 93. CryptoService cs = GetCryptoService(); 94. byte[] encrypted; 95. 96. if (cs.Encrypt(bToEncrypt, out encrypted)) 97. { 98. return Authenticator == CryptoHelper.ToBase64String(encrypted); 99. } 100. else 101. { 102. return false; 103. } 104. } 105. 106. 107. /// <summary> 108. /// 创建认证中心发往各分站的 Token 109. /// </summary> 110. /// <param name="ssoRequest"></param> 111. /// <returns></returns> 112. public static bool CreateEACToken(SSORequest ssoRequest) 113. { 114. string OriginalAuthenticator = ssoRequest.UserAccount + ssoRequest.IASID + ssoRequest.TimeStamp + ssoRequest.AppUrl; 115. string AuthenticatorDigest = CryptoHelper.ComputeHashString(OriginalAuthenticator); 116. string sToEncrypt = OriginalAuthenticator + AuthenticatorDigest; 117. byte[] bToEncrypt = CryptoHelper.ConvertStringToByteArray(sToEncrypt); 118. 119. CryptoService cs = GetCryptoService(); 120. byte[] encrypted; 121. 122. if (cs.Encrypt(bToEncrypt, out encrypted)) 123. { 124. ssoRequest.Authenticator = CryptoHelper.ToBase64String(encrypted); 125. 126. return true; 127. } 128. else 129. { 130. return false; 131. } 132. } 133. 134. 135. /// <summary> 136. /// 验证从认证中心发送过来的 Token 137. /// </summary> 138. /// <param name="ssoRequest"></param> 139. /// <returns></returns> 140. public static bool ValidateEACToken(SSORequest ssoRequest) 141. { 142. string Authenticator = ssoRequest.Authenticator; 143. 144. string OriginalAuthenticator = ssoRequest.UserAccount + ssoRequest.IASID + ssoRequest.TimeStamp + ssoRequest.AppUrl; 145. string AuthenticatorDigest = CryptoHelper.ComputeHashString(OriginalAuthenticator); 146. string sToEncrypt = OriginalAuthenticator + AuthenticatorDigest; 147. byte[] bToEncrypt = CryptoHelper.ConvertStringToByteArray(sToEncrypt); 148. 149. string EncryCurrentAuthenticator = string.Empty; 150. CryptoService cs = GetCryptoService(); 151. byte[] encrypted; 152. 153. if (cs.Encrypt(bToEncrypt, out encrypted)) 154. { 155. EncryCurrentAuthenticator = CryptoHelper.ToBase64String(encrypted); 156. 157. return Authenticator == EncryCurrentAuthenticator; 158. } 159. else 160. { 161. return false; 162. } 163. } 164. 165. 166. /// <summary> 167. /// 创建 EAC 认证中心的 Cookie 168. /// </summary> 169. /// <param name="userAccount"></param> 170. /// <param name="timeStamp"></param> 171. /// <param name="expireTime"></param> 172. /// <param name="cookieValue"></param> 173. /// <returns></returns> 174. public static bool CreatEACCookie(string userAccount, string timeStamp, string expireTime) 175. { 176. string plainText = "UserAccount=" + userAccount + ";TimeStamp=" + timeStamp + ";ExpireTime=" + expireTime; 177. plainText += hashSplitter + CryptoHelper.ComputeHashString(plainText); 178. 179. CryptoService cs = GetCryptoService(); 180. byte[] encrypted; 181. 182. if (cs.Encrypt(CryptoHelper.ConvertStringToByteArray(plainText), out encrypted)) 183. { 184. string cookieValue = CryptoHelper.ToBase64String(encrypted); 185. SetCookie(cookieValue); 186. 187. return true; 188. } 189. else 190. { 191. return false; 192. } 193. } 194. 195. /// <summary> 196. /// 验证 EAC 认证中心的 Cookie,验证通过时获取用户登录账号 197. /// </summary> 198. /// <param name="userAccount">输出用户登录账号</param> 199. /// <returns></returns> 200. public static bool ValidateEACCookie(out string userAccount) 201. { 202. userAccount = string.Empty; 203. try 204. { 205. 206. string cookieValue = GetCookie().Value; 207. byte[] toDecrypt = CryptoHelper.FromBase64String(cookieValue); 208. CryptoService cs = GetCryptoService(); 209. 210. string decrypted = string.Empty; 211. if (cs.Decrypt(toDecrypt, out decrypted)) 212. { 213. 214. string[] arrTemp = decrypted.Split(Convert.ToChar(hashSplitter)); 215. string plainText = arrTemp[0]; 216. string hashedText = arrTemp[1]; 217. 218. userAccount = plainText.Split(Convert.ToChar(";"))[0].Split(Convert.ToChar("="))[1]; 219. 220. return hashedText.Replace("\0", string.Empty) == CryptoHelper.ComputeHashString(plainText); 221. 222. } 223. else 224. { 225. return false; 226. } 227. } 228. catch (Exception e) 229. { 230. return false; 231. } 232. } 233. 234. 235. public static void Logout() 236. { 237. HttpContext.Current.Response.Cookies[cookieName].Expires = DateTime.Parse("1900-1-1"); 238. HttpContext.Current.Response.Cookies[cookieName].Path = "/"; 239. } 240. 241. private static void SetCookie(string cookieValue) 242. { 243. HttpContext.Current.Response.Cookies[cookieName].Value = cookieValue; 244. HttpContext.Current.Response.Cookies[cookieName].Expires = DateTime.Now.AddHours(24); 245. HttpContext.Current.Response.Cookies[cookieName].Path = "/"; 246. } 247. 248. private static HttpCookie GetCookie() 249. { 250. HttpCookie cookie = HttpContext.Current.Request.Cookies["EACToken"]; 251. return cookie; 252. } 253.}
CryptoHelper.cs
1.using System; 2.using System.Collections.Generic; 3.using System.Text; 4.using System.Security.Cryptography; 5. 6.public class CryptoHelper 7.{ 8. /// <summary> 9. /// 复合 Hash:string --> byte[] --> hashed byte[] --> base64 string 10. /// </summary> 11. /// <param name="s"></param> 12. /// <returns></returns> 13. public static string ComputeHashString(string s) 14. { 15. return ToBase64String(ComputeHash(ConvertStringToByteArray(s))); 16. } 17. 18. 19. public static byte[] ComputeHash(byte[] buf) 20. { 21. //return ((HashAlgorithm)CryptoConfig.CreateFromName("SHA1")).ComputeHash(buf); 22. return SHA1.Create().ComputeHash(buf); 23. 24. } 25. 26. /// <summary> 27. /// //System.Convert.ToBase64String 28. /// </summary> 29. /// <param name="buf"></param> 30. /// <returns></returns> 31. public static string ToBase64String(byte[] buf) 32. { 33. return System.Convert.ToBase64String(buf); 34. } 35. 36. 37. public static byte[] FromBase64String(string s) 38. { 39. return System.Convert.FromBase64String(s); 40. } 41. 42. /// <summary> 43. /// //Encoding.UTF8.GetBytes(s) 44. /// </summary> 45. /// <param name="s"></param> 46. /// <returns></returns> 47. public static byte[] ConvertStringToByteArray(String s) 48. { 49. return Encoding.UTF8.GetBytes(s);//gb2312 50. } 51. 52. 53. public static string ConvertByteArrayToString(byte[] buf) 54. { 55. //return System.Text.Encoding.GetEncoding("utf-8").GetString(buf); 56. 57. return Encoding.UTF8.GetString(buf); 58. } 59. 60. 61. /// <summary> 62. /// 字节数组转换为十六进制字符串 63. /// </summary> 64. /// <param name="buf"></param> 65. /// <returns></returns> 66. public static string ByteArrayToHexString(byte[] buf) 67. { 68. StringBuilder sb = new StringBuilder(); 69. for (int i = 0; i < buf.Length; i++) 70. { 71. sb.Append(buf[i].ToString("X").Length == 2 ? buf[i].ToString("X") : "0" + buf[i].ToString("X")); 72. } 73. return sb.ToString(); 74. } 75. 76. /// <summary> 77. /// 十六进制字符串转换为字节数组 78. /// </summary> 79. /// <param name="s"></param> 80. /// <returns></returns> 81. public static byte[] HexStringToByteArray(string s) 82. { 83. Byte[] buf = new byte[s.Length / 2]; 84. for (int i = 0; i < buf.Length; i++) 85. { 86. buf[i] = (byte)(Char2Hex(s.Substring(i * 2, 1)) * 0x10 + Char2Hex(s.Substring(i * 2 + 1, 1))); 87. } 88. return buf; 89. } 90. 91. 92. private static byte Char2Hex(string chr) 93. { 94. switch (chr) 95. { 96. case "0": 97. return 0x00; 98. case "1": 99. return 0x01; 100. case "2": 101. return 0x02; 102. case "3": 103. return 0x03; 104. case "4": 105. return 0x04; 106. case "5": 107. return 0x05; 108. case "6": 109. return 0x06; 110. case "7": 111. return 0x07; 112. case "8": 113. return 0x08; 114. case "9": 115. return 0x09; 116. case "A": 117. return 0x0a; 118. case "B": 119. return 0x0b; 120. case "C": 121. return 0x0c; 122. case "D": 123. return 0x0d; 124. case "E": 125. return 0x0e; 126. case "F": 127. return 0x0f; 128. } 129. return 0x00; 130. } 131.}
CryptoService.cs
1.using System; 2.using System.Data; 3.using System.Configuration; 4.using System.Web; 5.using System.Web.Security; 6.using System.Web.UI; 7.using System.Web.UI.WebControls; 8.using System.Web.UI.WebControls.WebParts; 9.using System.Web.UI.HtmlControls; 10.using System.Text; 11.using System.Security.Cryptography; 12.using System.IO; 13. 14.public class CryptoService 15.{ 16. /// <summary> 17. /// 加密的密钥 18. /// </summary> 19. string sKey = "22362E7A9285DD53A0BBC2932F9733C505DC04EDBFE00D70"; 20. string sIV = "1E7FA9231E7FA923"; 21. 22. byte[] byteKey; 23. byte[] byteIV; 24. 25. /// <summary> 26. /// 加密向量 27. /// </summary> 28. static byte[] bIV ={ 1, 2, 3, 4, 5, 6, 7, 8 }; 29. 30. public CryptoService() 31. { } 32. 33. public CryptoService(string key, string IV) 34. { 35. sKey = key; 36. sIV = IV; 37. 38. byteKey = CryptoHelper.HexStringToByteArray(sKey); 39. byteIV = CryptoHelper.HexStringToByteArray(sIV); 40. } 41. 42. 43. 44. /// <summary> 45. /// 将明文加密,返回密文 46. /// </summary> 47. /// <param name="Data">要加密的字串</param> 48. /// <returns></returns> 49. public byte[] Encrypt(string Data) 50. { 51. try 52. { 53. byte[] ret; 54. 55. using (MemoryStream mStream = new MemoryStream()) 56. using (CryptoStream cStream = new CryptoStream(mStream, 57. new TripleDESCryptoServiceProvider().CreateEncryptor(byteKey, byteIV), 58. CryptoStreamMode.Write)) 59. { 60. 61. byte[] toEncrypt = new ASCIIEncoding().GetBytes(Data); 62. 63. // Write the byte array to the crypto stream and flush it. 64. cStream.Write(toEncrypt, 0, toEncrypt.Length); 65. cStream.FlushFinalBlock(); 66. 67. // Get an array of bytes from the 68. // MemoryStream that holds the 69. // encrypted data. 70. ret = mStream.ToArray(); 71. 72. } 73. 74. return ret; 75. } 76. catch (CryptographicException e) 77. { 78. //Console.WriteLine("A Cryptographic error occurred: {0}", e.Message); 79. return null; 80. } 81. 82. } 83. 84. 85. /// <summary> 86. /// 将明文加密,返回密文 87. /// </summary> 88. /// <param name="toEncrypt">明文</param> 89. /// <param name="encrypted">密文</param> 90. /// <returns></returns> 91. public bool Encrypt(byte[] toEncrypt, out byte[] encrypted) 92. { 93. encrypted = null; 94. try 95. { 96. // Create a new MemoryStream using the passed 97. // array of encrypted data. 98. // Create a CryptoStream using the MemoryStream 99. // and the passed key and initialization vector (IV). 100. using (MemoryStream mStream = new MemoryStream()) 101. using (CryptoStream cStream = new CryptoStream(mStream, 102. new TripleDESCryptoServiceProvider().CreateEncryptor(byteKey, byteIV), 103. CryptoStreamMode.Write)) 104. { 105. 106. // Write the byte array to the crypto stream and flush it. 107. cStream.Write(toEncrypt, 0, toEncrypt.Length); 108. cStream.FlushFinalBlock(); 109. 110. // Get an array of bytes from the 111. // MemoryStream that holds the 112. // encrypted data. 113. encrypted = mStream.ToArray(); 114. } 115. 116. return true; 117. } 118. catch (CryptographicException e) 119. { 120. //Console.WriteLine("A Cryptographic error occurred: {0}", e.Message); 121. return false; 122. } 123. 124. } 125. 126. 127. 128. /// <summary> 129. /// 将明文加密,返回 Base64 字符串 130. /// </summary> 131. /// <param name="Data"></param> 132. /// <returns></returns> 133. public string EncryptToString(string Data) 134. { 135. try 136. { 137. string base64String = string.Empty; 138. 139. using (MemoryStream mStream = new MemoryStream()) 140. using (CryptoStream cStream = new CryptoStream(mStream, 141. new TripleDESCryptoServiceProvider().CreateEncryptor(byteKey, byteIV), 142. CryptoStreamMode.Write)) 143. { 144. 145. byte[] toEncrypt = new ASCIIEncoding().GetBytes(Data); 146. 147. cStream.Write(toEncrypt, 0, toEncrypt.Length); 148. cStream.FlushFinalBlock(); 149. 150. byte[] ret = mStream.ToArray(); 151. 152. base64String = Convert.ToBase64String(ret); 153. } 154. 155. return base64String; 156. } 157. catch (CryptographicException e) 158. { 159. return null; 160. } 161. 162. } 163. 164. 165. /// <summary> 166. /// 将密文解密,返回明文 167. /// </summary> 168. /// <param name="Data">密文</param> 169. /// <returns>明文</returns> 170. public bool Decrypt(byte[] Data, out string decrypted) 171. { 172. decrypted = string.Empty; 173. try 174. { 175. 176. using (MemoryStream msDecrypt = new MemoryStream(Data)) 177. using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, 178. new TripleDESCryptoServiceProvider().CreateDecryptor(byteKey, byteIV), 179. CryptoStreamMode.Read)) 180. { 181. 182. byte[] fromEncrypt = new byte[Data.Length]; 183. 184. // Read the decrypted data out of the crypto stream 185. // and place it into the temporary buffer. 186. csDecrypt.Read(fromEncrypt, 0, fromEncrypt.Length); 187. 188. decrypted = Encoding.UTF8.GetString(fromEncrypt);//new ASCIIEncoding().GetString(fromEncrypt); 189. 190. return true; 191. } 192. } 193. catch (CryptographicException e) 194. { 195. return false; 196. } 197. } 198. 199.}
PostService.cs
1.using System; 2.using System.Collections.Generic; 3.using System.Text; 4. 5.public class PostService 6.{ 7. private System.Collections.Specialized.NameValueCollection Inputs = new System.Collections.Specialized.NameValueCollection(); 8. public string Url = ""; 9. public string Method = "post"; 10. public string FormName = "form1"; 11. 12. /// <summary> 13. /// 添加需要提交的名和值 14. /// </summary> 15. /// <param name="name"></param> 16. /// <param name="value"></param> 17. public void Add(string name, string value) 18. { 19. Inputs.Add(name, value); 20. } 21. 22. /// <summary> 23. /// 以输出Html方式POST 24. /// </summary> 25. public void Post() 26. { 27. System.Web.HttpContext.Current.Response.Clear(); 28. 29. string html = string.Empty; 30. 31. html += ("<html><head>"); 32. html += (string.Format("</head><body onload=\"document.{0}.submit()\">", FormName)); 33. html += (string.Format("<form name=\"{0}\" method=\"{1}\" action=\"{2}\" >", FormName, Method, Url)); 34. try 35. { 36. for (int i = 0; i < Inputs.Keys.Count; i++) 37. { 38. html += (string.Format("<input name=\"{0}\" type=\"hidden\" value=\"{1}\">", Inputs.Keys[i], Inputs[Inputs.Keys[i]])); 39. } 40. html += ("</form>"); 41. html += ("</body></html>"); 42. 43. System.Web.HttpContext.Current.Response.Write(html); 44. System.Web.HttpContext.Current.Response.End(); 45. } 46. catch (Exception ee) 47. { 48. // 49. } 50. } 51.}
SSORequest.cs
1.using System; 2.using System.Data; 3.using System.Configuration; 4.using System.Web; 5.using System.Web.Security; 6.using System.Web.UI; 7.using System.Web.UI.WebControls; 8.using System.Web.UI.WebControls.WebParts; 9.using System.Web.UI.HtmlControls; 10. 11.[Serializable] 12.public class SSORequest : MarshalByRefObject 13.{ 14. public string IASID; //各独立站点标识ID 15. public string TimeStamp; //时间戳 16. public string AppUrl; //各独立站点的访问地址 17. public string Authenticator; //各独立站点的 Token 18. 19. public string UserAccount; //账号 20. public string Password; //密码 21. 22. public string IPAddress; //IP地址 23. 24. //为ssresponse对象做准备 25. public string ErrorDescription = "认证失败"; //用户认证通过,认证失败,包数据格式不正确,数据校验不正确 26. public int Result = -1; 27. 28. public SSORequest() 29. { 30. 31. } 32. 33. 34. /// <summary> 35. /// 获取当前页面上的SSORequest对象 36. /// </summary> 37. /// <param name="CurrentPage"></param> 38. /// <returns></returns> 39. public static SSORequest GetRequest(Page CurrentPage) 40. { 41. SSORequest request = new SSORequest(); 42. request.IPAddress = CurrentPage.Request.UserHostAddress; 43. request.IASID = CurrentPage.Request["IASID"].ToString();// Request本身会Decode 44. request.UserAccount = CurrentPage.Request["UserAccount"].ToString();//this.Text 45. request.Password = CurrentPage.Request["Password"].ToString(); 46. request.AppUrl = CurrentPage.Request["AppUrl"].ToString(); 47. request.Authenticator = CurrentPage.Request["Authenticator"].ToString(); 48. request.TimeStamp = CurrentPage.Request["TimeStamp"].ToString(); 49. return request; 50. } 51.}
配置web.config
1.<authentication mode="Forms"> 2. <forms name=".AspxFormAuth" loginUrl="Default.aspx" defaultUrl="center.html" protection="All" path="/" timeout="60"> 3. </forms> 4. </authentication> 5. <authorization> 6. <!--拒绝所有匿名用户--> 7. <deny users="?"/> 8. </authorization> <authentication mode="Forms"> <forms name=".AspxFormAuth" loginUrl="Default.aspx" defaultUrl="center.html" protection="All" path="/" timeout="60"> </forms> </authentication> <authorization> <!--拒绝所有匿名用户--> <deny users="?"/> </authorization>
最后效果如下:登录总站后,各站点之间无需再登录,可以互相访问。
另外,注销登录后,访问站点1 http://localhost/Site1/Default.aspx ,会自动跳转到主站登录页面 http://localhost/MasterSite/Default.aspx ,同样访问站点2 http://localhost/Site2/Default.aspx 也会转到主站登录页面。从主站登录后,分别访问站点1和站点2。
在IIS配置虚拟目录MasterSite Site1 Site2,当然你也可以新建站点MasterSite Site1 Site2,修改hosts表 127.0.0.1 http://www.mastersite.com/
127.0.0.1 http://www.site1.com/
127.0.0.1 http://www.site2.com/
源代码下载:http://download.csdn.net/source/1571879