c#

位置:IT落伍者 >> c# >> 浏览文章

.NET单点登陆的实现方法及思路


发布日期:2023年08月07日
 
.NET单点登陆的实现方法及思路
这篇文章介绍了NET单点登陆的实现方法及思路有需要的朋友可以参考一下希望对你有所帮助

系统的基本架构
我们假设一个系统System包含Service客户服务中心Shop网上购物中心和Office网上办公中心三个独立的网站  Service管理客户的资料登录和注销过程不论客户访问System的任何一个页面系统都会转到登录界面在用户登录后系统会自动转会到客户上  次请求的页面并且用户此后可以在System中无缝切换不需要再次进行登录即在System中实现单点登录SSO(Single  SignOn)
我们知道用户的即时状态通常是使用ApplicationSessionCookie和存储的而这些都是不能在程序中跨站点访问的我们必需通过站点间相互通讯来确认用户的即时状态
简单的实现
第一步假设用户访问了Shop或Office的任何一个页面Any该页面所在的网站将会检查用户的即时状态如果用户已经登录了则将  Any页面的信息返回给用户如果用户还没有登录则自动转到Service的Validate页面验证用户在Service状态即Shop或  Office向Service发出请求要求Service返回用户的即时状态
第二步Validate验证用户的即时状态如果  用户已经登录了则Service将用户的即时状态返回给Shop或Office的同步页面  Synchronous通知Shop或Office同步用户状态如果用户没有登录则自动转向Customer页面提示用户登录
第三步用户完成登录过程当用户成功登录后自动转回Validate页面通知Shop或Office的Synchronous进行用户状态的同步
第四步在用户状态同步完成后在本地站点用户状态成为在线状态即可访问Any页面
在上面的流程中我们知道不管用户访问哪个站点用户只需要一次登录就保证用户在Service的即时状态都是在线的不会再需要进行第二次登录的过程
现在我们的思路已经清楚具体的实现我们将在代码分析中完成
代码分析
从上面的流程中我们可以看出系统中Shop和Office的代码是完全类似的只要Shop可以实现Office也可以同样的克隆所以我们的重点分析的对象是Shop和Service的代码
Shop的Webconfig和Projectcs
在Shop的Webconfig里我们配置了Service站点和Shop站点以方便我们在部署时方便修改

复制代码 代码如下:
<appsettings>
<add key="Service" value="http://localhost:" />
<add key="WebSite" value="http://localhost:" />
</appsettings>


在Project类里进行引用

复制代码 代码如下:
using System;
using SystemConfiguration;
namespace AmethystureSSOShop
{
public class Project
{
public static string Service = ConfigurationSettingsAppSettings["Service"];
public static string WebSite = ConfigurationSettingsAppSettings["WebSite"];
}
}


Shop的Globalcs
  Shop的Globalcs定义了四个Session变量UserID用来标识用  户身份Pass标识用户即时状态Security用于保存往来Service和Shop的通讯不是被仿冒的Url保存了上次请求的页面以保证在用  户登录后能转到用户请求的页面

复制代码 代码如下:
protected void Session_Start(Object sender EventArgs e)
{
thisSessionAdd("UserID" );
thisSessionAdd("Pass" false);
thisSessionAdd("Security" "");
thisSessionAdd("Url" "");
}


Shop的Anycs
Shop的Anycs并没有包含代码因为Any类从Page继承而来为了代码分析方便我们将代码集中到Pagecs中

复制代码 代码如下:
using System;
using SystemWeb;
namespace AmethystureSSOShop
{
public class Any : AmethystureSSOShopPage
{
}
}


Shop的Pagecs
Page类有两个方法CustomerValidate和InitializeCustomerValidate用户检查用户的即时状态而Initialize是页面登录后发送给用户的信息我们的重点是CustomerValidate
CustomerValidate是一个非常简单的流程用条件语句检查Pass的状态如果Pass为否则表示用户没有登录页面跳转到  Service的Validate页面中我们要分析的是其中保存的Url和递交的WebSite和Security几个参数Url的作用在前面已经讲   清楚了只是为了保证用户登录后能回到原来的页面而WebSite是为了保证该站点是被Service所接受的并且保证Service知道是哪个站点   请求了用户即时状态因为这个例子是个简单的例子在后面的Validate里没有验证WebSite是否是接受的请求站点但是在实际应用中应该验证这  一点因为Shop和Service等同于服务器和客户端服务器出于安全考虑必须要检查客户端是否是被允许的Security是非常重要的一点  Shop对Service发送的是请求不需要保证该请求没有被篡改但是在Service应答Shop请求时就必须要保证应答的数据没有被篡改了  Security正是为了保证数据安全而设计的
在代码中Security是通过Hash一个随机产生的数字生成的具有不确定  性和保密性我们可以看到Security同时保存在Session中和发送给Service我们把这个Security当作明文在后面我们可以  看到Security在Service经过再一次Hash后作为密文发送回Shop如果我们将Session保存的Security经过同样的  Hash方法处理后等到的字符串如果和Service返回的密文相同我们就能够在一定程度上保证Service应答的数据是没有经过修改的

复制代码 代码如下:
using System;
using SystemWeb;
using SystemSecurityCryptography;
using SystemText;
namespace AmethystureSSOShop
{
public class Page : SystemWebUIPage
{
private void CustomerValidate()
{
bool Pass = (bool) thisSession["Pass"];
if (!Pass)
{
string Security = "";
Random Seed = new Random();
Security = SeedNext( intMaxValue)ToString();
byte[] Value;
UnicodeEncoding Code = new UnicodeEncoding();
byte[] Message = CodeGetBytes(Security);
SHAManaged Arithmetic = new SHAManaged();
Value = ArithmeticComputeHash(Message);
Security = "";
foreach(byte o in Value)
{
Security += (int) o + "O";
}
thisSession["Security"] = Security;
thisSession["Url"] = thisRequestRawUrl;
thisResponseRedirect(ProjectService + "/Validateaspx?WebSite=" + ProjectWebSite + "&Security=" + Security);
}
}
protected virtual void Initialize()
{
thisResponseWrite("<html>");
thisResponseWrite("<head>");
thisResponseWrite("<title>Amethysture SSO Project</title>");
thisResponseWrite("<link rel=stylesheet type="text/css" href="" + projectwebsite + "/Defaultcss">");
thisResponseWrite("</head>");
thisResponseWrite("<body>");
thisResponseWrite("<iframe width="" height="" src="" + projectservice + "/Customeraspx"></iframe>");
thisResponseWrite("<div align="center">");
thisResponseWrite("Amethysture SSO Shop Any Page");
thisResponseWrite("</div>");
thisResponseWrite("</body>");
thisResponseWrite("</html>");
}
protected override void OnInit(EventArgs e)
{
baseOnInit(e);
thisCustomerValidate();
thisInitialize();
thisResponseEnd();
}
}
}


Service的Globalcs
现在我们页面转到了Service的Validate页面我们转过来看  Service的代码在Global中我们同样定义了四个Session变量都和Shop的Session用处类似WebSite是保存请求用户即  时状态的站点信息以便能在登录后返回正确的请求站点

复制代码 代码如下:
protected void Session_Start(Object sender EventArgs e)
{
thisSessionAdd("UserID" );
thisSessionAdd("Pass" false);
thisSessionAdd("WebSite" "");
thisSessionAdd("Security" "");
}


Service的Validatecs
首先将Shop传递过来的参数保存到Session中如果用户没有登录则转到Customer页面进行登录如果用户已经登录了则将用户即时状态传回给Shop站点如上所述这里将Security重新Hash了一次传回给Shop以保证数据不被纂改

复制代码 代码如下:
private void CustomerValidate()
{
bool Pass = (bool) thisSession["Pass"];
if ((thisRequestQueryString["WebSite"] != null) && (thisRequestQueryString["WebSite"] != ""))
{
thisSession["WebSite"] = thisRequestQueryString["WebSite"];
}
if ((thisRequestQueryString["Security"] != null) && (thisRequestQueryString["Security"] != ""))
{
thisSession["Security"] = thisRequestQueryString["Security"];
}
if (Pass)
{
string UserID = thisSession["UserID"]ToString();
string WebSite = thisSession["WebSite"]ToString();
string Security = thisSession["Security"]ToString();
byte[] Value;
UnicodeEncoding Code = new UnicodeEncoding();
byte[] Message = CodeGetBytes(Security);
SHAManaged Arithmetic = new SHAManaged();
Value = ArithmeticComputeHash(Message);
Security = "";
foreach(byte o in Value)
{
Security += (int) o + "O";
}
thisResponseRedirect(WebSite + "/Synchronousaspx?UserID=" + UserID + "&Pass=True&Security=" + Security);
}
else
{
thisResponseRedirect("Customeraspx");
}
}


Service的Customercs和Logincs
  Customer主要的是一个用于登录的表单这里就不  贴出代码了这里分析一下Login的一段代码这段代码是当登录是直接在Service完成的(WebSite为空值)则页面不会转到Shop或  Office站点所以应该暂停在Service站点系统如果比较完美这里应该显示一组字系统的转向链接下面我们看到当Pass为真时页面转回  到Validate页面通过上面的分析我们知道页面会转向Shop的Synchronous页面进行用户状态的同步

复制代码 代码如下:
if (Pass)
{
if ((thisSession["WebSite"]ToString() != "") && (thisSession["Security"]ToString() != ""))
{
thisResponseRedirect("Validateaspx");
}
else
{
thisResponseWrite("");
thisResponseWrite("");
thisResponseWrite("");
thisResponseWrite("");
thisResponseWrite("");
thisResponseWrite("");
thisResponseWrite("");
thisResponseWrite("Pass");
thisResponseWrite("");
thisResponseWrite("");
thisResponseWrite("");
}
}
else
{
thisResponseRedirect("Customeraspx");
}


Shop的Synchronouscs
  好了我们在Service中完成了登录并把用户状态传递回Shop站  点我们接着看用户状态是怎么同步的首先如果Session里的Security是空字符串则表示Shop站点没有向Service发送过请求而  Service向Shop发回了请求这显然是错误的这次访问是由客户端伪造进行的访问于是访问被拒绝了同样Security和  InSecurity不相同则表示请求和应答是不匹配的可能应答被纂改过了所以应答同样被拒绝了当检验Security通过后我们保证  Serive完成了应答并且返回了确切的参数下面就是读出参数同步Shop站点和Service站点的用户即时状态

复制代码 代码如下:
string InUserID = thisRequestQueryString["UserID"];
string InPass = thisRequestQueryString["Pass"];
string InSecurity = thisRequestQueryString["Security"];
string Security = thisSession["Security"]ToString();
if (Security != "")
{
byte[] Value;
UnicodeEncoding Code = new UnicodeEncoding();
byte[] Message = CodeGetBytes(Security);
SHAManaged Arithmetic = new SHAManaged();
Value = ArithmeticComputeHash(Message);
Security = "";
foreach(byte o in Value)
{
Security += (int) o + "O";
}
if (Security == InSecurity)
{
if (InPass == "True")
{
thisSession["UserID"] = intParse(InUserID);
thisSession["Pass"] = true;
thisResponseRedirect(thisSession["Url"]ToString());
}
}
else
{
thisResponseWrite("");
thisResponseWrite("");
thisResponseWrite("");
thisResponseWrite("");
thisResponseWrite("");
thisResponseWrite("");
thisResponseWrite("");
thisResponseWrite("数据错误");
thisResponseWrite("");
thisResponseWrite("");
thisResponseWrite("");
}
}
else
{
thisResponseWrite("");
thisResponseWrite("");
thisResponseWrite("");
thisResponseWrite("");
thisResponseWrite("");
thisResponseWrite("");
thisResponseWrite("");
thisResponseWrite("访问错误");
thisResponseWrite("");
thisResponseWrite("");
thisResponseWrite("");
}


Shop的Pagecs
  我们知道页面在一段时间不刷新后Session会超时失效在我们一直访问Shop的  时候怎么才能保证Service的Session不会失效呢?很简单我们返回来看Shop的Pagecs通过在所有Shop的页面内都用  <iframe>嵌套Service的某个页面就能保证Service能和Shop的页面同时刷新需要注意的一点是Service的Session必  须保证不小于所有Shop和Office的Session超时时间这个在Webconfig里可以进行配置

复制代码 代码如下:
thisResponseWrite("<iframe width="" height="" src="" + projectservice + "/Customeraspx"></iframe>");


总结
一次完整的登录完成了我们接着假设一下现在要跳到Office的Any页面系统会进行怎样的操作  呢?Any(用户没有登录)>Validate(用户已经登录)>Synchronous(同步)>Any也就是说这次用户没有进行登录的过  程我们通过一次登录使得Service的用户状态为登录并且不管有多少个网站应用只要这些网站都保证符合Shop的特性这些网站就都能保持  Service的用户状态同时能通过Service获得用户的状态也就是说我们实现了SSO

               

上一篇:深入分析ADO.NET中的DataSet对象

下一篇:C# 获取网页html源文件