- 浏览: 145763 次
- 性别:
- 来自: 成都
文章分类
最新评论
-
老八牛:
利用迭代器让异步操作更加“人性化”-山寨版的AsyncEnumerator -
老八牛:
为什么看不到代码?
利用迭代器让异步操作更加“人性化”-山寨版的AsyncEnumerator -
xi4nyu:
如果启动Application中的settings 的debu ...
玩蛇记-使用Tornado构建高性能Web之二-autoreload -
huacnlee:
"且在python下工作多日才发现原来在.NET下的 ...
玩蛇记-使用tornado构建高性能Web应用之一 -
jasongreen:
异步数据库操作,在web上有什么作用吗?
玩蛇记-使用tornado构建高性能Web应用之一
费了一夜的功夫写完这些代码,有些凌乱,望见谅。
首先是对加密解密的抽象,因为.NET对3DES的实现很龌龊,不支持String,所以我们必须把他封装为可以用String作为Key,IV,输入和输出的3DES加密类,这个很重要,对Cookie的加密和解密和对URL的加密解密都靠它了
using System;
using System.Collections.Generic;
using System.Text;
using System.Security;
using System.Security.Cryptography;
namespace Alexander.SSOLib.Cryptography
{
public class Decrypter
{
private ICryptoTransform decrypter;
public Decrypter(string Key, string IV)
{
System.Security.Cryptography.TripleDES des = System.Security.Cryptography.TripleDESCryptoServiceProvider.Create();
des.Key = Common.Str2Byte(Key);
des.IV = Common.Str2Byte(IV);
des.Mode = CipherMode.ECB;
des.Padding = PaddingMode.PKCS7;
decrypter = des.CreateDecryptor();
}
public string DecryptString(string InputString)
{
byte[] input = Common.Str2Byte(InputString);
byte[] output = decrypter.TransformFinalBlock(input, 0, input.Length);
return Common.NormalByte2Str(output);
}
}
}
这里我们看看核心在这里
System.Security.Cryptography.TripleDES des = System.Security.Cryptography.TripleDESCryptoServiceProvider.Create();
得到了3des处理程序的实例,注意TripleDES是基类,这里是个典型Factory或者是Builder,看不到内部实现,猜的。
在这里要设置Key和IV才可以使用,让人无比郁闷的是,Key和IV都需要byte数组,所以不得不把输入的字符串转换一次,我们看到调用了Common类的静态方法。这里我们来看看这个Common类
using System;
using System.Collections.Generic;
using System.Text;
namespace Alexander.SSOLib.Cryptography
{
public class Common
{
public static byte[] Str2Byte(string Str)
{
return Convert.FromBase64String(Str);
}
public static string Byte2Str(Byte[] Byt)
{
return Convert.ToBase64String(Byt);
}
public static Byte[] NormalStr2Byte(string str)
{
return Encoding.Default.GetBytes(str);
}
public static string NormalByte2Str(byte[] Byt)
{
return Encoding.Default.GetString(Byt);
}
}
}
这里有四个方法,分别是:
Convert.FromBase64String(Str);
Convert.ToBase64String(Byt);
Encoding.Default.GetBytes(str);
Encoding.Default.GetString(Byt);
这里分别对Base64编码的字符串,和默认字符集得字符串与Byte[]之间的转换方法,这里要用Str2Byte(string Str)这个方法,其他几个我们后面用
why用Base64呢?因为我们把Key和IV的Byte数组可以用Base64编码成字符串就成了5dI2LJtk/z/gIEa0XsN66lASdvNHBmUV这样子的字符串,如果使用其他方式就成了乱码了。
在设置了Key和IV后就是显示设定一下填充模式等属性,其实没什么必要。
然后通过
des.CreateDecryptor();创建一个转换器实例,ICryptoTransform接口所定义的。
通过decrypter.TransformFinalBlock的时候就能转换了,注意输入的字符串需要Base64转换,输出字符串需要当前系统字符集创建。
加密类的结构和解密类差不多,不过输入用当前字符集转换到byte数组,而输出用Base64的方法,和解密是反过来的。
然后是Common里面的数据结构与操作类
KeyManager 管理Key和IV的
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
namespace Alexander.SSOLib.Common
{
public class KeyManager
{
private static string storebase;
static KeyManager()
{
storebase = System.Configuration.ConfigurationSettings.AppSettings["StoreBase"];
}
public static void GetKeyBySiteID(string ID,out string Key,out string IV)
{
string path = (storebase.EndsWith("\\")?storebase:storebase+"\\") + ID + ".Key"
if (File.Exists(path))
{
using (StreamReader reader = new StreamReader(path))
{
Key=reader.ReadLine();
IV = reader.ReadLine();
reader.Close();
}
}
else
{
Key = ""
IV = ""
}
}
public static void UpdateKey(string SiteID)
{
string path = (storebase.EndsWith("\\") ? storebase : storebase + "\\") + SiteID + ".Key"
using (StreamWriter writer = new StreamWriter(path,false,Encoding.Default))
{
Alexander.SSOLib.Cryptography.KeyMaker km = new Alexander.SSOLib.Cryptography.KeyMaker();
writer.WriteLine(km.Key);
writer.WriteLine(km.Iv);
writer.Flush();
writer.Close();
}
}
public static void DeleteKey(string SiteID)
{
string path = (storebase.EndsWith("\\") ? storebase : storebase + "\\") + SiteID + ".Key"
File.Delete(path);
}
}
}
PSORequest表示PSO端的请求
using System;
using System.Collections.Generic;
using System.Text;
using Alexander.SSOLib.Cryptography;
namespace Alexander.SSOLib.Common
{
public class PSORequest
{
private string Key=System.Configuration.ConfigurationSettings.AppSettings["Key"];
private string IV=System.Configuration.ConfigurationSettings.AppSettings["IV"];
private string siteid;
public string Siteid
{
get { return siteid; }
set { siteid = value; }
}
private string createdate;
public string Createdate
{
get { return createdate; }
set { createdate = value; }
}
private string returnurl;
public string Returnurl
{
get { return returnurl; }
set { returnurl = value; }
}
public PSORequest()
{
siteid = System.Configuration.ConfigurationSettings.AppSettings["SiteID"];
createdate = DateTime.Now.ToString();
returnurl = System.Web.HttpContext.Current.Request.Url.ToString();
}
public PSORequest(string HashString)
{
string[] rls = HashString.Split('$');
string sKey;
string sIV;
KeyManager.GetKeyBySiteID(rls[0], out sKey, out sIV);
Decrypter de = new Decrypter(sKey, sIV);
string rs = de.DecryptString(rls[1]);
string[] sp = rs.Split('|');
siteid = rls[0];
createdate = sp[0];
returnurl = sp[1];
}
public string CreateHash()
{
Encrypter en = new Encrypter(Key, IV);
return siteid + "$" + en.EncryptString(createdate + "|" + Returnurl);
}
}
}
这里我们可以看见 请求的数据包括站点的ID和3DES加密后的会话时间和返回的地址。
public PSORequest()是PSO端实例化的构造器,创建一个空的请求,并且通过方法
CreateHash()来创建一个加密的字符串。
public PSORequest(string HashString)在SSO端用来解析PSO请求的格式,然后把值写入对象的变量内
SSOResponse类包含了SSO端向PSO发送的反馈URL的格式的类
using System;
using System.Collections.Generic;
using System.Text;
using Alexander.SSOLib.Cryptography;
namespace Alexander.SSOLib.Common
{
public class SSOResponse
{
private string Key = System.Configuration.ConfigurationSettings.AppSettings["Key"];
private string IV = System.Configuration.ConfigurationSettings.AppSettings["IV"];
private PSORequest request;
private string Response;
public SSOResponse(PSORequest Request)
{
request = Request;
}
public SSOResponse(string SSOResponse)
{
Response = SSOResponse;
}
public string CreateResponseString(Ticket ticket)
{
ticket.Createdate=request.Createdate;
string data = request.Siteid + "|" + ticket.Userid + "|" + ticket.Username + "|" + ticket.Ticketdata + "|" + ticket.Createdate;
string sKey;
string sIV;
KeyManager.GetKeyBySiteID(request.Siteid,out sKey,out sIV);
Encrypter enc = new Encrypter(sKey, sIV);
return enc.EncryptString(data);
}
public Ticket CreatePSOTicket()
{
Decrypter dc = new Decrypter(Key, IV);
string data = dc.DecryptString(Response.Trim().Replace(" ","+"));
string[] ls = data.Split('|');
Ticket tc = new Ticket(ls[0], ls[1], ls[2], ls[3]);
return tc;
}
}
}
同样的,有两个构造器,一个在PSO端用,一个在SSO端用。原理和PSORequest差不多。
Ticket类包含了Cookie的结构和加密解密,加载和保存的操作
using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using Alexander.SSOLib.Cryptography;
namespace Alexander.SSOLib.Common
{
public class Ticket
{
private Encrypter enc;
private Decrypter dec;
private string Key = System.Configuration.ConfigurationSettings.AppSettings["Key"];
private string IV = System.Configuration.ConfigurationSettings.AppSettings["IV"];
private string userid=""
public string Userid
{
get { return dec.DecryptString(userid); }
set { userid = enc.EncryptString(value); }
}
private string username=""
public string Username
{
get { return dec.DecryptString(username); }
set { username = enc.EncryptString(value); }
}
private string ticketdata=""
public string Ticketdata
{
get { return dec.DecryptString(ticketdata); }
set { ticketdata = enc.EncryptString(value); }
}
private string createdate=""
public string Createdate
{
get { return dec.DecryptString(createdate); }
set { createdate = enc.EncryptString(value); }
}
public Ticket(string UserID, string UserName, string TicketData, string CreateDate)
{
enc = new Encrypter(Key, IV);
dec = new Decrypter(Key, IV);
userid = enc.EncryptString(UserID);
username = enc.EncryptString(UserName);
ticketdata = enc.EncryptString(TicketData);
createdate = enc.EncryptString(CreateDate);
}
public Ticket()
{
enc = new Encrypter(Key, IV);
dec = new Decrypter(Key, IV);
}
public bool LoadTicket(string domain)
{
if (System.Web.HttpContext.Current.Request.Cookies[domain] != null)
{
userid = System.Web.HttpContext.Current.Request.Cookies[domain]["UserID"];
username = System.Web.HttpContext.Current.Request.Cookies[domain]["UserName"];
ticketdata = System.Web.HttpContext.Current.Request.Cookies[domain]["TicketDate"];
return true;
}
else
{
return false;
}
}
public void SaveTicket(string domain)
{
System.Web.HttpContext.Current.Response.Cookies[domain]["UserID"] = userid;
System.Web.HttpContext.Current.Response.Cookies[domain]["UserName"] = username;
System.Web.HttpContext.Current.Response.Cookies[domain]["TicketDate"] = ticketdata;
}
}
}
经过以上层次的抽象,于是我们来看看PSOClient
using System;
using System.Collections.Generic;
using System.Text;
using Alexander.SSOLib.Common;
namespace Alexander.SSOLib.PSO
{
public class PSOClient:System.Web.IHttpModule
{
#region IHttpModule 成员
System.Web.HttpApplication Context;
public void Dispose()
{
// throw new Exception("The method or operation is not implemented.");
}
public void Init(System.Web.HttpApplication context)
{
Context = context;
context.BeginRequest += new EventHandler(context_BeginRequest);
}
void context_BeginRequest(object sender, EventArgs e)
{
string ExceptList = "$$" + System.Configuration.ConfigurationSettings.AppSettings["Exceptlist"];
if (ExceptList.IndexOf(Context.Request.Url.ToString()) < 1)
{
string Key = System.Configuration.ConfigurationSettings.AppSettings["SSOKey"];
string ssoresponse = Context.Request.QueryString[Key];
SSOResponse sr = new SSOResponse(ssoresponse);
if (ssoresponse != null)
{
Ticket tc = sr.CreatePSOTicket();
tc.SaveTicket(System.Configuration.ConfigurationSettings.AppSettings["domain"]);
}
else
{
Ticket tc = new Ticket();
if (!tc.LoadTicket(System.Configuration.ConfigurationSettings.AppSettings["domain"]))
{
PSORequest request = new PSORequest();
string requeststr = request.CreateHash();
string KeeperUrl = System.Configuration.ConfigurationSettings.AppSettings["KeeperUrl"];
Context.Response.Redirect(KeeperUrl + "?" + Key + "=" + Context.Server.UrlEncode(requeststr));
}
}
}
}
#endregion
}
}
一个典型的HttpModule,逻辑清晰简单,很好懂
SSO也是差不多。
最后看看完整的代码:http://www.cnblogs.com/Files/Alexander-Lee/SSO.rar
发表评论
-
关于ORM和内存数据库的遐想
2007-01-23 13:21 571最近有消息说韩国电信 ... -
继续ORM-欧德巴赫猜想-Mapping
2007-01-23 14:34 666最近从项目组单离出来开始在公司实施过程化管理,整个QA Off ... -
剑走偏锋,小心走火入魔
2007-01-23 15:07 707这是很久前写好的文字,闲得无聊就发上来,几个月前的感想,上午一 ... -
手把手教你写ORM(三)
2007-01-24 11:50 606昨天处于晕死状态,少写了一个组件,还需要一个组件用来专门管理C ... -
手把手教你写ORM(四)
2007-01-24 13:51 641现在中午不睡一会儿就头晕。前一篇有人留言说为什么不写web.c ... -
手把手教你写ORM(五)
2007-01-24 15:29 605CMMI是魔鬼继续上面的内容,这里我们要实现一个插件的结构来动 ... -
谈谈我们的学习和我们的Blog
2007-01-24 20:07 407第一,学习编程是一个很枯燥的过程,所以我们更要讲究效率(要把有 ... -
手把手教你写代码生成器(也算ORM的续)
2007-01-25 11:45 725因为ORM还是需要配置,还是需要EntityObject,所以 ... -
粒度细到控件的权限管理系统的设计(概要篇)
2007-01-25 21:40 1067其实这个设计是已经做过了,那个时候我才进公司还在试用期,给我的 ... -
粒度细到控件的权限管理组件(构想篇)
2007-01-26 10:34 748说老实话我现在还没开 ... -
手把手教你写ORM大全篇
2007-01-26 19:36 680根据dudu boss的建议将本系列作一个归纳,下一个系列正在 ... -
架构设计的非侵入性原则
2007-01-27 00:41 698最近常常看到JAVA社区热 ... -
手把手教你可复用SSO组件的设计(原理篇)
2007-01-27 14:55 759在结构设计上复用性 ... -
对《万事欠备设计先行》的一点想法,兼谈XP和CMMI
2007-01-29 09:31 651周末陪女友,故沉默了,其实大脑并没有沉默,之前看到《万事欠备设 ... -
手把手教你可复用的SSO组件设计(设计篇)
2007-01-29 16:24 593周末陪女朋友去了,没写,告罪,上班后急忙补上。 这里说到了可复 ... -
玩具级嵌入式内存对象数据库^V^
2007-02-01 19:46 496纯粹是为了好玩:} 最近几天很忙所以写得少了,昨天在清理硬盘的 ... -
差之毫厘谬以千里-计算中的精度问题
2007-02-27 10:04 587如果你只是i++来作计数 ... -
动态语言,涅磐重生还是死路一条?
2007-03-06 10:31 581最近花时间一直在看python和ruby,为了在Web应用又看 ... -
ASP.NET's MVC is what a joke!
2007-03-08 13:43 477很早前还在毁人不倦的 ... -
对分词的一些看法,最近看到不少,不说不快
2007-03-19 10:51 522关于分词得研究由来已久,最近看到博客园里类似文章不断,于是想说 ...
相关推荐
在提供的"单点登陆(SSO)组件的设计与实现.doc"文档中,可能会详细介绍SSO组件的架构设计、实现步骤、技术选型,以及如何将这些组件集成到实际应用中的具体细节。同时,"SSO.rar"可能是源代码包,包含了SSO组件的实现...
本项目提供了一款基于C#编写的SSO组件源码,其设计思路类似于微软的认证服务器和Web应用服务器,能够实现跨域和跨服务器的身份验证。 首先,理解C#中的SSO实现原理至关重要。SSO的核心在于票据(Ticket)的概念,当...
SSO的实现通常涉及到以下几个关键组件: 1. **认证中心(Identity Provider, IDP)**:这是SSO的核心,负责用户的登录验证。在SSO系统中,用户只需向IDP提供用户名和密码。 2. **服务提供者(Service Provider, SP...
CAS框架SSO的实现
以下是对SSO简单实现的详细说明: 在实现SSO时,有多种方法可以选择: 1. **商业软件**:一些大型公司如 Netgrity(Siteminder)、Novell(iChain)、RSA(ClearTrust)等提供专门的SSO解决方案。这些软件通常具备...
Java Web SSO(Single Sign...总之,Java Web SSO的实现涉及到多个组件和协议,需要对身份验证、会话管理以及相关开源技术有深入理解。开发者应关注安全性、用户体验和系统的可扩展性,以构建高效且可靠的SSO解决方案。
SSO(Single Sign-On)单点登录是一种身份验证机制,允许用户在多个相互关联的应用系统中只需要登录一次,即可访问所有...了解SSO的实现原理和源码分析,对于IT从业者来说,无论是系统设计还是故障排查,都将大有裨益。
CAS(Central Authentication Service)是一种广泛使用的开放源码的单点登录(Single ...在提供的文档《手把手教你利用CAS实现单点登录.docx》中,你将找到更详细的步骤和示例代码,帮助你更好地理解和实施CAS SSO。
在本文中,我们将深入探讨如何使用SSM(Spring MVC、Spring、MyBatis)框架结合Redis缓存来实现SSO功能。 首先,了解SSO的核心原理是关键。SSO主要依赖于票据(Ticket)的概念,当用户成功登录到一个系统时,服务器...
Java单点登录(Single Sign-On, SSO)的实现是一个复杂但重要的任务,尤其是在大型企业或组织中,它能够提供用户友好的访问体验,减少多次输入凭证的繁琐过程。SSO技术的应用通常涉及到多系统间的身份验证整合,使得...
SSO(单点登录)实战篇:客户端实现(1)1.Tomcat多应用部署的配置2.Maven项目的打包与发布3.客户端模块的主流程
在本文中,我们将探讨SSO的基本原理、实现方式以及一个简单的SSO系统的设计。 **SSO基本原理** SSO的核心是通过共享一种信任关系来实现跨系统的身份验证。这种信任通常由一个中央认证服务(CAS,Central ...
二、.NET SSO实现的关键组件 1. 认证中心:负责用户的身份验证,为用户提供登录界面,并生成认证令牌。 2. 应用系统:需要与认证中心进行交互,验证用户的身份,并接受认证令牌。 3. 协议支持:例如CAS(Central ...
spring boot整合spring security 实现SSO单点登陆 完整DEMO. ...2、先后启动SsoServer、sso-resource、sso-client1、sso-client2 3、访问http://sso-taobao:8083/client1/ 或 http://sso-tmall:8084/client2/
下面我们将深入剖析SSO技术的实现原理及其关键组成部分。 1. **SSO原理**: SSO的核心思想是用户只需在一个“认证中心”进行身份验证,之后便可以在所有信任该认证中心的应用系统中自由切换,无需再次输入凭证。这...
5. 提供高可用性:通过把认证过的状态数据存储在TicketRegistry组件中,这些组件有很多支持分布式环境的实现,如:BerkleyDB、Default、EhcacheTicketRegistry、JDBCTicketRegistry、JBOSS TreeCache、...