- 浏览: 138899 次
- 性别:
- 来自: 成都
文章分类
最新评论
-
老八牛:
利用迭代器让异步操作更加“人性化”-山寨版的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 535最近有消息说韩国电信 ... -
继续ORM-欧德巴赫猜想-Mapping
2007-01-23 14:34 631最近从项目组单离出来开始在公司实施过程化管理,整个QA Off ... -
剑走偏锋,小心走火入魔
2007-01-23 15:07 675这是很久前写好的文字,闲得无聊就发上来,几个月前的感想,上午一 ... -
手把手教你写ORM(三)
2007-01-24 11:50 575昨天处于晕死状态,少写了一个组件,还需要一个组件用来专门管理C ... -
手把手教你写ORM(四)
2007-01-24 13:51 597现在中午不睡一会儿就头晕。前一篇有人留言说为什么不写web.c ... -
手把手教你写ORM(五)
2007-01-24 15:29 572CMMI是魔鬼继续上面的内容,这里我们要实现一个插件的结构来动 ... -
谈谈我们的学习和我们的Blog
2007-01-24 20:07 364第一,学习编程是一个很枯燥的过程,所以我们更要讲究效率(要把有 ... -
手把手教你写代码生成器(也算ORM的续)
2007-01-25 11:45 671因为ORM还是需要配置,还是需要EntityObject,所以 ... -
粒度细到控件的权限管理系统的设计(概要篇)
2007-01-25 21:40 1025其实这个设计是已经做过了,那个时候我才进公司还在试用期,给我的 ... -
粒度细到控件的权限管理组件(构想篇)
2007-01-26 10:34 711说老实话我现在还没开 ... -
手把手教你写ORM大全篇
2007-01-26 19:36 637根据dudu boss的建议将本系列作一个归纳,下一个系列正在 ... -
架构设计的非侵入性原则
2007-01-27 00:41 658最近常常看到JAVA社区热 ... -
手把手教你可复用SSO组件的设计(原理篇)
2007-01-27 14:55 726在结构设计上复用性 ... -
对《万事欠备设计先行》的一点想法,兼谈XP和CMMI
2007-01-29 09:31 606周末陪女友,故沉默了,其实大脑并没有沉默,之前看到《万事欠备设 ... -
手把手教你可复用的SSO组件设计(设计篇)
2007-01-29 16:24 554周末陪女朋友去了,没写,告罪,上班后急忙补上。 这里说到了可复 ... -
玩具级嵌入式内存对象数据库^V^
2007-02-01 19:46 459纯粹是为了好玩:} 最近几天很忙所以写得少了,昨天在清理硬盘的 ... -
差之毫厘谬以千里-计算中的精度问题
2007-02-27 10:04 547如果你只是i++来作计数 ... -
动态语言,涅磐重生还是死路一条?
2007-03-06 10:31 541最近花时间一直在看python和ruby,为了在Web应用又看 ... -
ASP.NET's MVC is what a joke!
2007-03-08 13:43 455很早前还在毁人不倦的 ... -
对分词的一些看法,最近看到不少,不说不快
2007-03-19 10:51 488关于分词得研究由来已久,最近看到博客园里类似文章不断,于是想说 ...
相关推荐
SSO的简单实现SSO的简单实现SSO的简单实现
CAS框架SSO的实现
下载前请参考这篇文章http://blog.csdn.net/javaee_ssh/article/details/25998553
SSO(单点登录)实战篇:客户端实现(1)1.Tomcat多应用部署的配置2.Maven项目的打包与发布3.客户端模块的主流程
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单点登录的实现源代码,以及实现原理详解,有需要的可以看看。
里面存放了源代码和文档,可提供给各位研究
java单点登录的实现与应用整合中SSO的技术实现
C#单点登陆组件源码SSO(类似微软认证服务器和WEB应用服务器,可跨域跨服务器...)
公司需要做统一的sso单点登录,由于CAS过于重量级和复杂。所以就自己基于springMVC mybatis redis缓存实现了SSO单点登录。mark一下!
sso的实现机制
本文有两个部分: 第一部分: EOS 与 SSO有联系吗? 第二部分:作者本人对SSO的理解和实现。
Yale CAS 3.3实现SSO详细教程。
sso的原理与java实现
OAuth2+ SSO实现单点登录,包括源码...网上关于实现SSO的文章一大堆,但是当你真的照着写的时候就会发现根本不是那么回事儿,简直让人抓狂,尤其是对于我这样的菜鸟。几经曲折,终于搞定了,决定记录下来,以便后续查看
利用springMvc 实现的简单的单点登录Demo,内含三个小Mavn项目分别是 1、认证中心SSOServer 2、子系统1SSOClient1 3、子系统2SSOClient2 文章请参考 http://blog.csdn.net/qq_31183297/article/details/79419222
Java EE和Domino系统间跨域SSO的实现
SSO单点登录数据库设计,上一个文件忘记上传数据库设计。本次上传加上
使用CAS框架实现SSO单点登录,其中包含: 1、CAS服务器端安装包 2、客户端源码包和所需的所有jar包 3、CAS+框架+SSO的实现.pdf 5、CAS+SSO实例安装和配置指南PDF版.rar 6、Tomcat中使用Yale+CAS实现单点登陆(SSO)....