- 浏览: 148767 次
- 性别:
- 来自: 成都
-
文章分类
最新评论
-
老八牛:
利用迭代器让异步操作更加“人性化”-山寨版的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 585最近有消息说韩国电信 ... -
继续ORM-欧德巴赫猜想-Mapping
2007-01-23 14:34 683最近从项目组单离出来开始在公司实施过程化管理,整个QA Off ... -
剑走偏锋,小心走火入魔
2007-01-23 15:07 721这是很久前写好的文字,闲得无聊就发上来,几个月前的感想,上午一 ... -
手把手教你写ORM(三)
2007-01-24 11:50 623昨天处于晕死状态,少写了一个组件,还需要一个组件用来专门管理C ... -
手把手教你写ORM(四)
2007-01-24 13:51 671现在中午不睡一会儿就头晕。前一篇有人留言说为什么不写web.c ... -
手把手教你写ORM(五)
2007-01-24 15:29 634CMMI是魔鬼继续上面的内容,这里我们要实现一个插件的结构来动 ... -
谈谈我们的学习和我们的Blog
2007-01-24 20:07 422第一,学习编程是一个很枯燥的过程,所以我们更要讲究效率(要把有 ... -
手把手教你写代码生成器(也算ORM的续)
2007-01-25 11:45 757因为ORM还是需要配置,还是需要EntityObject,所以 ... -
粒度细到控件的权限管理系统的设计(概要篇)
2007-01-25 21:40 1079其实这个设计是已经做过了,那个时候我才进公司还在试用期,给我的 ... -
粒度细到控件的权限管理组件(构想篇)
2007-01-26 10:34 760说老实话我现在还没开 ... -
手把手教你写ORM大全篇
2007-01-26 19:36 712根据dudu boss的建议将本系列作一个归纳,下一个系列正在 ... -
架构设计的非侵入性原则
2007-01-27 00:41 716最近常常看到JAVA社区热 ... -
手把手教你可复用SSO组件的设计(原理篇)
2007-01-27 14:55 773在结构设计上复用性 ... -
对《万事欠备设计先行》的一点想法,兼谈XP和CMMI
2007-01-29 09:31 670周末陪女友,故沉默了,其实大脑并没有沉默,之前看到《万事欠备设 ... -
手把手教你可复用的SSO组件设计(设计篇)
2007-01-29 16:24 608周末陪女朋友去了,没写,告罪,上班后急忙补上。 这里说到了可复 ... -
手把手教你可复用的SSO组件设计(实现篇)
2007-01-29 22:30 636费了一夜的功夫写完这些代码,有些凌乱,望见谅。 首先是对加密解 ... -
玩具级嵌入式内存对象数据库^V^
2007-02-01 19:46 509纯粹是为了好玩:} 最近几天很忙所以写得少了,昨天在清理硬盘的 ... -
差之毫厘谬以千里-计算中的精度问题
2007-02-27 10:04 600如果你只是i++来作计数 ... -
动态语言,涅磐重生还是死路一条?
2007-03-06 10:31 597最近花时间一直在看python和ruby,为了在Web应用又看 ... -
ASP.NET's MVC is what a joke!
2007-03-08 13:43 491很早前还在毁人不倦的 ...
相关推荐
13.4.2 基于面向对象设计实现播放器功能 467 13.4.3 面向对象封装、继承、多态的应用 468 13.4.4 设计模式、条件外置及反射技术的应用 471 13.5 面向对象分析(OOA)的方法 475 13.6 面向对象设计的原则 478 13.6.1 ...
13.4.2 基于面向对象设计实现播放器功能 467 13.4.3 面向对象封装、继承、多态的应用 468 13.4.4 设计模式、条件外置及反射技术的应用 471 13.5 面向对象分析(OOA)的方法 475 13.6 面向对象设计的原则 478 13.6.1 ...
街道级行政区划shp矢量数据,wgs84坐标系,下载直接使用
街道级行政区划shp数据,wgs84坐标系,直接下载使用。
街道级行政区划shp矢量数据,wgs84坐标系,下载直接使用
轻量级密码算法LBlock的FPGA优化实现.docx
街道级行政区划shp矢量数据,wgs84坐标系,下载直接使用
Git 资料 progit-zh-v2.1.1.pdf
街道级行政区划shp数据,wgs84坐标系,直接下载使用。
篮球计分器FPGA附程序..doc
街道级行政区划shp数据,wgs84坐标系,直接下载使用。
内容概要:本文档全面介绍了Linux开发的基础知识、应用场景、环境搭建、常用命令、Shell脚本编程以及C/C++和Python开发等内容。首先阐述了Linux开发的重要性及其在服务器端开发、嵌入式开发和系统运维等领域的广泛应用。接着详细讲解了如何选择合适的Linux发行版并安装系统,配置开发环境,包括安装必要的开发工具和配置SSH服务。文档还深入讲解了Linux基础命令,如文件和目录操作、文件内容查看与编辑、进程管理和权限管理。此外,介绍了Shell脚本编程的基本语法,包括变量、条件语句、循环语句和函数定义。针对C/C++和Python开发,文档分别讲解了编译器安装、程序编写与编译、调试方法及使用虚拟环境等内容。最后,简要介绍了Linux内核开发的相关知识,包括下载编译内核、内核模块开发等,并推荐了相关学习资源。 适合人群:对Linux开发感兴趣的初学者及有一定经验的研发人员,尤其是希望深入掌握Linux开发技能的开发者。 使用场景及目标:①掌握Linux开发环境的搭建与配置;②熟悉Linux基础命令和Shell脚本编程;③学习C/C++和Python在Linux下的开发流程;④了解Linux内核开发的基本概念和技术。 阅读建议:此文档内容丰富,涵盖面广,建议读者根据自身需求选择性阅读,并结合实际操作进行练习。特别是对于初学者,应先掌握基础命令和开发环境的搭建,再逐步深入到编程语言和内核开发的学习。
街道级行政区划shp数据,wgs84坐标系,直接下载使用。
街道级行政区划shp数据,wgs84坐标系,直接下载使用。
街道级行政区划shp数据,wgs84坐标系,直接使用。
内容概要:本文档《word练习题.docx》是一份详细的Word操作练习指南,涵盖了从基础到高级的各种功能。文档分为三个主要部分:内容编辑、页面布局和高效文档。内容编辑部分包括文本格式化、段落设置、项目编号、制表位、边框与底纹等练习;页面布局部分涉及分节符、分栏、页眉页脚、水印等设置;高效文档部分则聚焦于样式管理、导航窗格、题注、书签、超级链接、脚注与尾注、交叉引用等功能。每个练习都有具体的操作步骤,帮助用户掌握Word的各种实用技巧。 适合人群:适用于Word初学者及希望提高Word技能的中级用户,尤其是需要频繁使用Word进行文档编辑和排版的办公人员。 使用场景及目标:①帮助用户熟悉Word的基本操作,如文本编辑、格式设置等;②提升用户的文档排版能力,学会设置复杂的页面布局;③提高工作效率,掌握高效文档管理技巧,如样式应用、题注和交叉引用等。 其他说明:此文档不仅提供了具体的练习题目,还附带了详细的步骤说明,用户可以根据指引逐步完成每个练习。此外,文档中的一些练习涉及到智能文档和Office智能客户端的应用,有助于用户了解Word在企业级应用中的潜力。建议用户按照章节顺序逐步学习,实践每一个练习,以达到最佳的学习效果。
街道级行政区划shp数据,wgs84坐标系,直接下载使用。
全球腐败感知数据(2000-2023)——3000行 33个指标 关于数据集 该数据集包含3000行和33列,涵盖了2000年至2023年的腐败感知指数(CPI)数据和各种治理指标。它包括国家排名、分数和其他指标,如公共部门腐败、司法腐败、贿赂指数、商业道德、民主指数、法治、政府效率、经济指标和人类发展指数。 这些数据可用于: 腐败趋势分析 腐败对GDP、人类发展指数和治理的影响 跨国比较 数据可视化和机器学习模型 该数据集对研究人员、数据分析师、政策制定者和对研究全球腐败趋势非常有用。
毕业设计(论文) 基于FPGA的数字频率计设计.doc
街道级行政区划shp数据,wgs84坐标系,直接使用。