(1) 通过单点登录SSO,这方面有现成的方案,如LDAP+CAS,然后还要建立一个统一的基础数据平台,这一套基于SOA面向服务的方案,确实比较好,也比较全面,同时复杂度也很高,推行起来非常困难,主要有以下几点:(1)各系统开发的语言不同,部署的环境也不同,如果接入这样一个平台则要单独出售时部署工作量很大,组件太多也容易出错,并且后期的维护也非常困难;(2)改造工作量大;(3)所有系统本身就有自己的一套认证系统,并入后用户同步会很多问题,如新增用户或删除了用户。由于这些原因,经过了近一年的推广,目前仍没有非常好的效果;
(2) 从框架上规范,推出一套完整的框架,所以人都按照框架的规范开发,自然也容易进行集成,当然这时java 与.net需要各自做一套,不同语言之间是不能集成了,但这个方案本身对框架要求较高,特别是不同系统对数据库、并发性、缓存、工作流等要求都不相同,当然还有其它许多问题;
(3) 一种轻量级的简单易行的整合方案,即通过cookie方式共享方式,把一些小的组件整合进来,如讨论、即时交流、产资管理等小的子系统。此方案实质上并不能说是完全的整合集成,而仅时完成了身份验证,确定角色等简单的集成,也只适合于一些小的组件(对权限要求不高也不需要分布式部署情况),下面将重点分析该方案。
基于cookie方式对接详解
(1) 主系统在登录时需要写一个COOKIE,其中包含了用户名、用户ID、主系统中的用户角色,但不限于这些信息,把这些信息保存到cookie中;代码如下:
UserDatauserdata = new UserData
{
UserId = userinfo.Id,
UserName = userinfo.UserName,
UserTypeId = userinfo.UserType_Id,
UserType = UserTypesManager.GetChinese(userinfo.UserType_Id.ToString()),
TeamId = termId,
VAUserIndex = SystemInfo.GetUserNameIndex(vAMaxIndex)
};
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
2,
userName,
DateTime.Now,
expiration,
isPersistent,
userdata == null ? "" :userdata.ToString(),
FormsAuthentication.FormsCookiePath
);
String str =FormsAuthentication.Encrypt(ticket);
HttpCookie cookie = newHttpCookie(FormsAuthentication.FormsCookieName, str);
(2) 子系统中不包含用户信息,只是从cookie中读取出这些信息放入到SESSION中,之后系统中的什么权限判断等就通过主系统中的角色来判断,但实质上子系统不会去维护真正的用户,也不用登录模块,如需登录则跳转到主系统的登录页面(在子系统的配置文件中指定),读取代码如下(这部分代码一般写在基类中,则在子类中即可直接使用这些信息):
privateFormsAuthenticationTicketGetTicket()
{
FormsAuthenticationTicket ticket;
String encryptedTicket= GetAuthCookieValue();
if (encryptedTicket == null) return null;
if (encryptedTicket.Length == 0) return null;
try
{
ticket = FormsAuthentication.Decrypt(encryptedTicket);
}
catch(Exception ex)
{
return null;
}
return ticket;
}
//从cookie字符串中分解出相关信息
publicUserData(string model)
{
string[] aryTmp;
string[] splitData = model.Split(',');
if (splitData.Length == 5)
{
//获取用户ID
aryTmp = splitData[0].Split('=');
if (aryTmp.Length == 2)
{
intintTmp = 0;
int.TryParse(aryTmp[1], out intTmp);
UserID = intTmp;
}
//获取用户名
aryTmp = splitData[1].Split('=');
if (aryTmp.Length == 2)
{
UserName = aryTmp[1];
}
//获取角色
aryTmp = splitData[2].Split('=');
if (aryTmp.Length == 2)
{
RolesArray = aryTmp[1].Split('|');
}
//获取权限
aryTmp = splitData[3].Split('=');
if (aryTmp.Length == 2)
{
Function =aryTmp[1].Split('|');
}
//获取真实姓名
aryTmp = splitData[4].Split('=');
if (aryTmp.Length == 2)
{
FullName = aryTmp[1];
}
//为了适应以前系统做了相应的兼容
Warned =false;
}
}
(3) 可能你会问,如何保证主系统角色与子系统色角一致?
子系统首先会定义几种这样的角色,当然还可以扩展出更多的角色,然后在对接时,再指定它们之间的映射关系,如下(当然也可以做到配置文件中):
子系统中已有角色:
publicenumUserRole : short
{
NotLogin = 0,
/// <summary>
/// 普通用户
/// </summary>
Member = 1,
/// <summary>
/// 信任用户
/// </summary>
TrustedMember = 2,
/// <summary>
/// 版主
/// </summary>
Moderator = 3,
/// <summary>
/// 管理员
/// </summary>
Admin = 10
}
给外部系统角色绑定一个上述角色
privateUserRoleGetRole(string role)
{
switch (role)
{
case "学生":
returnUserRole.Member;
case "教师":
returnUserRole.Moderator;
case "管理员":
returnUserRole.Admin;
default:
returnUserRole.Member;
}
}
(4) 如何保证cookie访问过程中的安全性?
虽然cookie在同一个域(IP或网址)中才共享,但为不被修改,或者不需望以明文形式存放,这时可以使用.net自带的加密算法,在写cookie时加密,在读取时解密,当然要求两个站点的加密串都必须相同,还有cookie的名称也要相同,配置部分片段如下:
<system.web>
<machineKeyvalidationKey="C50B3C89CB21F4F1422FF158A5B42D0E8DB8CB5CDA1742572A487D9401E3400267682B202B746511891C1BAF47F8D25C07F6C39A104696DB51F17C529AD3CABE"decryptionKey="8A9BE8FD67AF6979E7D20198CFEA50DD3D3799C77AF2B72F"validation="SHA1" />
<authentication mode="Forms"><formsloginUrl="/Account/LogOn" name="gtadtpwebui" timeout="2880"/>
(5) 布署和整合
通过上述过程后,即可把一个论坛嵌入到主系统中,页面中嵌入的方式,我推荐使用iframe方式,部署则最好采用虚拟目录方式,也可以独立的站点,但要求两个站点之间可以共享cookie即可。
(6) 局限性
l 权限对映不严格
l 配置有点复杂,特别是加密字符串和cookie名称不能错,否则无法打通
l 网站的风格可能与该子系统的风格差异很大,造成风格不一
在一些需求销有变动情况下,可能仍需对对接的代码块做一些修改才能适应需求。