解决思路如下:
请求认证的网站 :用一个HttpModule 截取所有请求,判断HttpContext.User是不是Null,如为空,判断Url上是不是有签名过的认证信息, 如果有,判断签名信息是否有效,如果有效,将认证信息写入Cookie中.认证完成
认证的网站: 如果登陆页Url中有要求认证的网址,判断用户是不是已授权,如果已授权,将用户信息签名,写入Url中
二个网站都使用的Form认证
代码
请求认证网站,HttpMoudle如下
1using System;
2using System.Collections.Generic;
3using System.Text;
4using System.Web;
5using System.Web.Security;
6using System.Security.Principal;
7
8namespace SSO
9{
10 /// <summary>
11 /// 单点认证的HttpModule
12 /// </summary>
13 public class SSOAuthenticateHttpModule:IHttpModule
14 {
15 public String ModuleName
16 {
17 get { return "SSOAuthenticateHttpModule"; }
18 }
19
20 IHttpModule 成员
135 }
136}
137
2using System.Collections.Generic;
3using System.Text;
4using System.Web;
5using System.Web.Security;
6using System.Security.Principal;
7
8namespace SSO
9{
10 /// <summary>
11 /// 单点认证的HttpModule
12 /// </summary>
13 public class SSOAuthenticateHttpModule:IHttpModule
14 {
15 public String ModuleName
16 {
17 get { return "SSOAuthenticateHttpModule"; }
18 }
19
20 IHttpModule 成员
135 }
136}
137
SSOClient 是一个助手类主要负责认证签名,设置Cookie,从Url中分离出认证信息
1using System;
2using System.Collections.Generic;
3using System.Text;
4using System.Security.Cryptography;
5using System.Security.Principal;
6using System.Web;
7using System.Web.Security;
8
9
10namespace SSO
11{
12 internal class SSOClient
13 {
14 private static String PublicKey = "公钥信息,我用的是RSA,你可以自己生成"
15 internal static bool ValidataData(String data, String signedData)
16 {
17 try
18 {
19 RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(512);
20 RSA.FromXmlString(PublicKey);
21
22 UnicodeEncoding ByteConverter = new UnicodeEncoding();
23
24 SHA1CryptoServiceProvider sha = new SHA1CryptoServiceProvider();
25 return RSA.VerifyData(ByteConverter.GetBytes(data), new SHA1CryptoServiceProvider(), Convert.FromBase64String(signedData));
26 }
27 catch
28 {
29 return false;
30 }
31
32 }
33
34 internal static String SplitUserName(String data)
35 {
36 UnicodeEncoding ByteConverter = new UnicodeEncoding();
37
38 return data.Split('$')[0];
39 }
40
41
42 internal static String SplitToken(String data)
43 {
44 UnicodeEncoding ByteConverter = new UnicodeEncoding();
45
46
47 return data.Split('$')[1];
48 }
49
50 internal static void SetAuthCookie(HttpContext context, String userName, String token, bool isPersistent)
51 {
52
53
54 FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
55 1, // Ticket version
56 userName, // Username associated with ticket
57 DateTime.Now, // Date/time issued
58 DateTime.Now.AddMinutes(30), // Date/time to expire
59 isPersistent, // "true" for a persistent user cookie
60 token, // User-data, in this case the roles
61 FormsAuthentication.FormsCookiePath);// Path cookie valid for
62
63 // Encrypt the cookie using the machine key for secure transport
64 string hash = FormsAuthentication.Encrypt(ticket);
65
66 HttpCookie cookie = new HttpCookie(
67 FormsAuthentication.FormsCookieName, // Name of auth cookie
68 hash); // Hashed ticket
69
70 // Set the cookie's expiration time to the tickets expiration time
71 if (ticket.IsPersistent) cookie.Expires = ticket.Expiration;
72
73 // Add the cookie to the list for outgoing response
74 context.Response.Cookies.Add(cookie);
75 }
76
77
78 }
79}
80
2using System.Collections.Generic;
3using System.Text;
4using System.Security.Cryptography;
5using System.Security.Principal;
6using System.Web;
7using System.Web.Security;
8
9
10namespace SSO
11{
12 internal class SSOClient
13 {
14 private static String PublicKey = "公钥信息,我用的是RSA,你可以自己生成"
15 internal static bool ValidataData(String data, String signedData)
16 {
17 try
18 {
19 RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(512);
20 RSA.FromXmlString(PublicKey);
21
22 UnicodeEncoding ByteConverter = new UnicodeEncoding();
23
24 SHA1CryptoServiceProvider sha = new SHA1CryptoServiceProvider();
25 return RSA.VerifyData(ByteConverter.GetBytes(data), new SHA1CryptoServiceProvider(), Convert.FromBase64String(signedData));
26 }
27 catch
28 {
29 return false;
30 }
31
32 }
33
34 internal static String SplitUserName(String data)
35 {
36 UnicodeEncoding ByteConverter = new UnicodeEncoding();
37
38 return data.Split('$')[0];
39 }
40
41
42 internal static String SplitToken(String data)
43 {
44 UnicodeEncoding ByteConverter = new UnicodeEncoding();
45
46
47 return data.Split('$')[1];
48 }
49
50 internal static void SetAuthCookie(HttpContext context, String userName, String token, bool isPersistent)
51 {
52
53
54 FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
55 1, // Ticket version
56 userName, // Username associated with ticket
57 DateTime.Now, // Date/time issued
58 DateTime.Now.AddMinutes(30), // Date/time to expire
59 isPersistent, // "true" for a persistent user cookie
60 token, // User-data, in this case the roles
61 FormsAuthentication.FormsCookiePath);// Path cookie valid for
62
63 // Encrypt the cookie using the machine key for secure transport
64 string hash = FormsAuthentication.Encrypt(ticket);
65
66 HttpCookie cookie = new HttpCookie(
67 FormsAuthentication.FormsCookieName, // Name of auth cookie
68 hash); // Hashed ticket
69
70 // Set the cookie's expiration time to the tickets expiration time
71 if (ticket.IsPersistent) cookie.Expires = ticket.Expiration;
72
73 // Add the cookie to the list for outgoing response
74 context.Response.Cookies.Add(cookie);
75 }
76
77
78 }
79}
80
被认证的网站的WebConfig文件
<?xml version="1.0"?>
<!--
注意: 除了手动编辑此文件以外,您还可以使用
Web 管理工具来配置应用程序的设置。可以使用 Visual Studio 中的
“网站”->“Asp.Net 配置”选项。
设置和注释的完整列表在
machine.config.comments 中,该文件通常位于
\Windows\Microsoft.Net\Framework\v2.x\Config 中
-->
<configuration>
<appSettings/>
<connectionStrings/>
<system.web>
<!--
设置 compilation debug="true" 将调试符号插入
已编译的页面中。但由于这会
影响性能,因此只在开发过程中将此值
设置为 true。
-->
<compilation debug="true">
<assemblies>
<add assembly="System.Security, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/></assemblies></compilation>
<!--
通过 <authentication> 节可以配置 ASP.NET 使用的
安全身份验证模式,
以标识传入的用户。
-->
<authentication mode="Forms">
<forms loginUrl="http://localhost/TestSSOServer/Default.aspx" name=".ASPXFORMSAUTH" protection="All" path="/" timeout="30" enableCrossAppRedirects="true"/>
</authentication>
<!--<authorization>
<deny users="?"/>
</authorization>-->
<httpModules>
<add name="SSOAuthenticateHttpModule" type="SSO.SSOAuthenticateHttpModule"/>
</httpModules>
<!--
如果在执行请求的过程中出现未处理的错误,
则通过 <customErrors> 节可以配置相应的处理步骤。具体说来,
开发人员通过该节可以配置
要显示的 html 错误页
以代替错误堆栈跟踪。
<customErrors mode="RemoteOnly" defaultRedirect="GenericErrorPage.htm">
<error statusCode="403" redirect="NoAccess.htm" />
<error statusCode="404" redirect="FileNotFound.htm" />
</customErrors>
-->
</system.web>
</configuration>
<!--
注意: 除了手动编辑此文件以外,您还可以使用
Web 管理工具来配置应用程序的设置。可以使用 Visual Studio 中的
“网站”->“Asp.Net 配置”选项。
设置和注释的完整列表在
machine.config.comments 中,该文件通常位于
\Windows\Microsoft.Net\Framework\v2.x\Config 中
-->
<configuration>
<appSettings/>
<connectionStrings/>
<system.web>
<!--
设置 compilation debug="true" 将调试符号插入
已编译的页面中。但由于这会
影响性能,因此只在开发过程中将此值
设置为 true。
-->
<compilation debug="true">
<assemblies>
<add assembly="System.Security, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/></assemblies></compilation>
<!--
通过 <authentication> 节可以配置 ASP.NET 使用的
安全身份验证模式,
以标识传入的用户。
-->
<authentication mode="Forms">
<forms loginUrl="http://localhost/TestSSOServer/Default.aspx" name=".ASPXFORMSAUTH" protection="All" path="/" timeout="30" enableCrossAppRedirects="true"/>
</authentication>
<!--<authorization>
<deny users="?"/>
</authorization>-->
<httpModules>
<add name="SSOAuthenticateHttpModule" type="SSO.SSOAuthenticateHttpModule"/>
</httpModules>
<!--
如果在执行请求的过程中出现未处理的错误,
则通过 <customErrors> 节可以配置相应的处理步骤。具体说来,
开发人员通过该节可以配置
要显示的 html 错误页
以代替错误堆栈跟踪。
<customErrors mode="RemoteOnly" defaultRedirect="GenericErrorPage.htm">
<error statusCode="403" redirect="NoAccess.htm" />
<error statusCode="404" redirect="FileNotFound.htm" />
</customErrors>
-->
</system.web>
</configuration>
认证网站,比较简单,有一个负责登陆的页面,我就在上面放了一个Button和一个TxtBox
1using System;
2using System.Data;
3using System.Configuration;
4using System.Web;
5using System.Web.Security;
6using System.Web.UI;
7using System.Web.UI.WebControls;
8using System.Web.UI.WebControls.WebParts;
9using System.Web.UI.HtmlControls;
10
11public partial class _Default : System.Web.UI.Page
12{
13 protected void Page_Load(object sender, EventArgs e)
14 {
15 if (!Page.IsPostBack)
16 {
17 //判断是不是已认证通过--这里只是简单写了,具体你是怎么认证的,就怎么写
18 if (Request.IsAuthenticated)
19 {
20 //回到请求认证的网站;
21 ReturnUrl();
22 }
23
24 }
25
26 }
27 protected void Button1_Click(object sender, EventArgs e)
28 {
29 FormsAuthentication.SetAuthCookie(TextBox1.Text,false);
30
31 ReturnUrl();
32
33 }
34
35 /// <summary>
36 /// 取得认证信息
37 /// </summary>
38 /// <returns></returns>
39 private String getAuthInfo()
40 {
41 String userName = User.Identity.Name;
42 String tokenValue = "这是一些附加信息,你可以写入角色什么的";//在我的应用中,我写的是一个Token
43 String time = System.DateTime.Now.ToString();
44
45 String v = userName + "$" + tokenValue ;
46
47 return v;
48
49
50 }
51
52 /// <summary>
53 /// 返回请求认证的网站
54 /// </summary>
55 private void ReturnUrl()
56 {
57
58 String strUrl = Request.QueryString["site"];
59
60 if (String.IsNullOrEmpty(strUrl))
61 {
62 return;
63 }
64
65 strUrl = HttpUtility.UrlDecode(strUrl);
66
67 //取得认证信息
68 String data = getAuthInfo();
69
70 写入签名信息
84
85 Response.Redirect(strUrl);
86
87
88 }
89}
90
2using System.Data;
3using System.Configuration;
4using System.Web;
5using System.Web.Security;
6using System.Web.UI;
7using System.Web.UI.WebControls;
8using System.Web.UI.WebControls.WebParts;
9using System.Web.UI.HtmlControls;
10
11public partial class _Default : System.Web.UI.Page
12{
13 protected void Page_Load(object sender, EventArgs e)
14 {
15 if (!Page.IsPostBack)
16 {
17 //判断是不是已认证通过--这里只是简单写了,具体你是怎么认证的,就怎么写
18 if (Request.IsAuthenticated)
19 {
20 //回到请求认证的网站;
21 ReturnUrl();
22 }
23
24 }
25
26 }
27 protected void Button1_Click(object sender, EventArgs e)
28 {
29 FormsAuthentication.SetAuthCookie(TextBox1.Text,false);
30
31 ReturnUrl();
32
33 }
34
35 /// <summary>
36 /// 取得认证信息
37 /// </summary>
38 /// <returns></returns>
39 private String getAuthInfo()
40 {
41 String userName = User.Identity.Name;
42 String tokenValue = "这是一些附加信息,你可以写入角色什么的";//在我的应用中,我写的是一个Token
43 String time = System.DateTime.Now.ToString();
44
45 String v = userName + "$" + tokenValue ;
46
47 return v;
48
49
50 }
51
52 /// <summary>
53 /// 返回请求认证的网站
54 /// </summary>
55 private void ReturnUrl()
56 {
57
58 String strUrl = Request.QueryString["site"];
59
60 if (String.IsNullOrEmpty(strUrl))
61 {
62 return;
63 }
64
65 strUrl = HttpUtility.UrlDecode(strUrl);
66
67 //取得认证信息
68 String data = getAuthInfo();
69
70 写入签名信息
84
85 Response.Redirect(strUrl);
86
87
88 }
89}
90
认证助手类
1using System;
2using System.Collections.Generic;
3using System.Text;
4using System.Security.Cryptography;
5
6namespace SSO
7{
8 public class SSOServer
9 {
10 private static String PrivateKey = "私钥信息,这个很重要,";
11
12 /// <summary>
13 /// 签 名用户信息
14 /// </summary>
15 /// <param name="data"></param>
16 /// <returns></returns>
17 public static String SignatueData(String data)
18 {
19 try
20 {
21 //Create a UnicodeEncoder to convert between byte array and string.
22 UnicodeEncoding ByteConverter = new UnicodeEncoding();
23
24 byte[] dataToSignatue = ByteConverter.GetBytes(data);
25
26 RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(512);
27 RSA.FromXmlString(PrivateKey);
28
29 String SignadString = Convert.ToBase64String(RSA.SignData(dataToSignatue, new SHA1CryptoServiceProvider()));
30 return SignadString;
31
32 }
33 catch
34 {
35 return String.Empty;
36 }
37 }
38 //把一个字符串Base64编码
39 public static String Base64String(String data)
40 {
41 try
42 {
43 //Create a UnicodeEncoder to convert between byte array and string.
44 UnicodeEncoding ByteConverter = new UnicodeEncoding();
45
46 byte[] dataToBase = ByteConverter.GetBytes(data);
47
48 return Convert.ToBase64String(dataToBase);
49 }
50 catch
51 {
52 return String.Empty;
53 }
54
55 }
56
57 }
58}
59
2using System.Collections.Generic;
3using System.Text;
4using System.Security.Cryptography;
5
6namespace SSO
7{
8 public class SSOServer
9 {
10 private static String PrivateKey = "私钥信息,这个很重要,";
11
12 /// <summary>
13 /// 签 名用户信息
14 /// </summary>
15 /// <param name="data"></param>
16 /// <returns></returns>
17 public static String SignatueData(String data)
18 {
19 try
20 {
21 //Create a UnicodeEncoder to convert between byte array and string.
22 UnicodeEncoding ByteConverter = new UnicodeEncoding();
23
24 byte[] dataToSignatue = ByteConverter.GetBytes(data);
25
26 RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(512);
27 RSA.FromXmlString(PrivateKey);
28
29 String SignadString = Convert.ToBase64String(RSA.SignData(dataToSignatue, new SHA1CryptoServiceProvider()));
30 return SignadString;
31
32 }
33 catch
34 {
35 return String.Empty;
36 }
37 }
38 //把一个字符串Base64编码
39 public static String Base64String(String data)
40 {
41 try
42 {
43 //Create a UnicodeEncoder to convert between byte array and string.
44 UnicodeEncoding ByteConverter = new UnicodeEncoding();
45
46 byte[] dataToBase = ByteConverter.GetBytes(data);
47
48 return Convert.ToBase64String(dataToBase);
49 }
50 catch
51 {
52 return String.Empty;
53 }
54
55 }
56
57 }
58}
59