J2EE-单点登陆

中讲到系统的权限控制模型,当时按照最小依赖和最大重用把 web系统权限控制划分成了业务逻辑、权限管理、权限验证、登陆代理、登陆服务、用户管理、业务逻辑数据库、业务权限数据库和用户数据库几个部分,现在开始逐一实现以上除业务逻辑的部分,今天发布的是单点登陆系统,也就是登陆代理和登陆服务。
 

基于COOKIE的单点登陆

      单点登陆就是只需要在访问第一个业务逻辑时输入用户验证信息,以后访问其他业务逻辑不需要再次输入用户验证信息,而不管业务逻辑的部署方式。
      要实现单点登陆,其实就是要让系统有记忆功能,能记住用户以前登陆过,下次登陆时就不再需要用户输入身份验证信息,就像有的论坛会让用户选择记住用户登陆状态,并且可以选择一个过期时间,这样在过期时间之内用户访问这个论坛,论坛会标记用户为已登陆状态。
      COOKIE是实现系统记忆功能的很好的工具, COOKIE有两种,一种成为内存 COOKIE,这种 COOKIE在用户关闭浏览器时失效,另外一种为文件 COOKIE,可以保存在用户的电脑系统中,并且可以设置一个过期时间,在过期时间内该 COOKIE都有效。 COOKIE的另一个特性是域,概念等同于 JAVA的包,当浏览器访问某个链接时,会把这个链接的域跟所有存在的 COOKIE的域进行对比,域匹配的 COOKIE将被自动发送到 WEB服务器。
      根据 COOKIE的生存周期和域特性,可以在登陆服务里面设置一个 COOKIE,这个 COOKIE用来标志用户是否已经登陆, COOKIE可以选择内存 COOKIE或者文件 COOKIE,因为 COOKIE是域相关的,所以只有登陆服务可以看到这个 COOKIE。由于用户访问业务逻辑时,如果登陆代理找不到用户凭证,就会去登陆服务那里登陆,这时登陆服务的策略为如果找不到这个 COOKIE,那么提示用户输入用户验证信息验证,如果找到这个 COOKIE,那么直接告诉登陆代理已经登陆。
      流程图如下:
 
用户访问某业务逻辑,业务逻辑向登陆代理获取用户凭证。
登陆代理首先在 SESSION中查找用户凭证,如果用户凭证存在,表明用户已经登陆过,返回用户凭证给业务逻辑,如果用户凭证不存在,则向登陆服务请求登陆。
 
登陆服务首先 COOKIE中查找用户凭证,如果用户凭证存在,表明用户已经登陆过,返回用户凭证给登陆代理,如果不存在,则转向登陆页面要求用户输入用户验证信息,然后验证用户登陆信息,验证通过后设置 COOKIE以备下次登陆请求使用。
 
登陆代理接收到登陆服务的返回后,解析出用户凭证,保存该用户凭证到 SESSION以备以后使用,然后返回该用户凭证给业务逻辑。
业务逻辑接收到登陆代理的用户凭证后,验证权限,验证通过处理业务逻辑相关功能。
上面的文字解释可能有点晕,看流程图应该比较清楚,文字解释可能只是画蛇添足。
      如果把业务逻辑和登陆代理等中间过程透明化,只保留用户和登陆服务,那么登陆过程就非常清晰,其实就是用户访问登陆服务的过程,因为登陆服务只有一个,所以对指定的用户来说,一旦用户登陆过,那么 COOKIE就存在,所以用户下次再访问登陆服务,那么就不再需要输入用户名密码等用户验证信息了。
      这里可能有一个疑惑,就是登陆代理为什么要把用户凭证保存到 SESSION?这是为了提高效率,如果登陆代理不保存用户凭证,那么每次业务逻辑要查询用户凭证时,登陆代理都要转向登陆服务去查询,因为业务逻辑可能和登陆服务不是部署在一个地方,那么登陆代理向登陆服务查询用户凭证的过程需要很长的等待时间,用户感觉就是系统反应迟钝。当然,也可以把用户凭证保存在业务逻辑里,但是这样业务逻辑就做了本来不属于他的事情,所以保存在登陆代理里比较合理。因为登陆代理和业务逻辑是部署在一个 WEB应用程序里,所以使用登陆代理的 SESSION保存用户凭证,可以保证在业务逻辑的生存期内,用户凭证一直有效。
 

COOKIE安全性

      COOKIE在登陆服务中用来保存用户凭证,在登陆代理中用来保存 SESSION
      假设用户 A是正常用户,通过登陆服务进行了登陆,用户凭证被 COOKIE记录下来,假设这时黑客 B截获了 A的用户凭证,那么当 B连接到登陆服务验证时, B可以把截获的用户凭证附加到 COOKIE中,因为登陆服务通过 COOKIE来判断登陆状态,所以登陆服务会认为 B以前登陆过,并且告诉登陆代理 B的用户凭证,这样 B就欺骗了登陆服务而拥有了用户 A的操作权限。
      首先应该避免用户凭证的 COOKIE泄露,在用户端,因为内存 COOKIE比文件 COOKIE更难被截取,特别是经过特殊处理的浏览器,要截取内存 COOKIE几乎不可能,而且当浏览器关闭时,内存 COOKIE失效,所以应该使用内存 COOKIE而非文件 COOKIE,这也是很多使用文件 COOKIE的论坛帐号经常被盗的原因。
      其次,为进一步减少风险,不应该在 COOKIE中直接保存用户凭证,而是使用一个无意义的标识符如 UUID来表示,而登陆服务可以通过这个 UUID查找到真正的用户凭证,这个标志符随机生成,即使同一用户登陆,得到的 UUID也不一样,所以不能重复使用,这样即使偶尔泄露一次,也不会造成长期影响。为了提高 COOKIE的截取难度,可以设置一个有效时间,只有在有效期内的 COOKIE是合法的,超过有效期的 COOKIE将被忽略,使用超过有效期的用户依然需要重新输入验证信息。这样也带来一个不便的地方,就是用户如果两次业务逻辑之间的切换时间超过了 COOKIE的有效期,那么用户还得重新输入验证信息,达不到单点登陆的效果,所以如何取舍,要根据业务逻辑而定。
其次因为 http使用明文传输,通过网络侦听的方式很容易获取 COOKIE,所以用户到登陆服务间的连接应该采用 https
      然后考察登陆代理中使用 COOKIE来保存 SESSION的情况,这是大多数 Web应用服务器采用的方法。这种情况类似登陆服务使用 COOKIE来保存用户凭证,典型的欺骗是黑客 B截获了正常用户 ASESSION COOKIE,然后 B访问业务逻辑时附带这个 COOKIEWeb应用服务器会认为 B就是 A,于是 A能得到的用户凭证, B也能得到, B就成了 A的影子,与 A具有相同的操作权限。所以关键问题还是如何避免 SESSION COOKIE的泄露,因为这个 COOKIEWeb应用服务器控制,所以除了在网络传输时使用 https,基本上没有其他办法可以降低风险。除了使用 COOKIE作为 SESSION标记,很多 Web应用服务器也支持隐式域的方式,就是 Web应用服务器在页面自动创建一个隐藏的表单项作为 SESSION标记,页面提交时该表单自动被提交, Web应用服务器通过这个表单项来确定用户 SESSION。这个是更不安全的做法,因为很多很简单的方法就可以获取页面表单项的数据,比获取内存 COOKIE容易很多。
 

消息传递安全性

      业务逻辑、登陆代理、登陆服务间存在消息传递,业务逻辑和登陆代理部署在一个 Web应用服务器中,消息传递比较安全。登陆代理和登陆服务通常处在不同的 Web应用服务器中,并且通常在地域上也不一致,登陆代理和登陆服务间的安全隐患除了消息泄露,还有相互信任的问题。
 
      首先是消息泄露,使用 https可以避免消息泄露。
      其次是登陆代理和登陆服务间如何相互信任,这就需要安全证书。关于证书的更多信息参考 http://en.wikipedia.org/wiki/Certificate_authority,也可以去 google搜索。证书的原理是基于非对称加密和数字摘要,非对称加密由一对密钥 (p, s)组成,使用 p加密的数据只能使用 s解密,使用 s加密的数据只能使用 p解密,著名的非对称加密算法是 RSA,数字摘要通过一个不可逆运算可以把数据 a变成数据 bb通常数据长度固定并且很小,而且不能用过 b反运算得到 a,常用的数字摘要算法有 MD5SHA1
      制作证书时,首先将证书信息 i使用数字摘要算法如 SHA1进行运算得到 ss = SHA1(i),然后把 is使用非对称加密算法如 RSAs加密得到证书 cc = RSA(s, i+s)。获取证书信息刚好是一个逆过程, i+s = RSA(p, c),然后把 is分离,并且比较 sSHA1(i)是否一致,如果一致,则这个证书信息是可信赖的。
      证书通常由权威机构制作,这个机构妥善保管 s,公布 p,那么互不相识的 AB通信, A要核对 B的身份, A要求 B的证书,然后核对解密后的证书信息就可以了。
      同样登陆代理和登陆服务在传递信息时也要核对身份,否则黑客可以将登陆代理引导到假冒的登陆服务,或者传递给登陆代理预先设定的用户凭证,进行认证欺骗。使用证书后,登陆代理请求登陆服务进行登陆时,首先核对登陆服务的证书,登陆代理处理登陆服务返回的用户凭证时,也核对登陆服务的证书,双方信息传递在 https中进行,所以存在消息篡改和泄漏,保证登陆服务是可信赖的。登陆服务的证书必须妥善保管,并且定期更换。
      也可以根据证书原理自定义处理过程,登陆代理和登陆服务各自掌握 ps,证书代理发送消息使用 p加密,接收消息使用 p解密,登陆服务接收消息使用 s解密,发送消息使用 s加密,消息附带 SHA1数字摘要,这样登陆代理和登陆服务也可相互信任。这种方案下,可以不使用 https,因为消息已经被加密。但是这样有一个漏洞,就是会被重播,比如黑客可以截获登陆服务发送给登陆代理的整个加密的消息,然后完整地发送给登陆代理,这样登陆代理不能识别究竟真伪而被欺骗。可以在消息里面附加随机数据来解决这个漏洞,登陆代理发送消息前,先随机产生一段数据,并附加到消息中,然后加密发送给登陆服务,登陆服务发送消息给登陆代理时也附带这个数据,登陆代理核对这个数据来确定有效性,每次登陆代理和登陆服务传输的数据都不一样,重播不再有效。

安装部署

我用的版本是 Tomcat5523+MySQL5037+jre1.5.0_12,没在其他版本下测试过。
1.下载 cglib最新版本 http://cglib.sourceforge.net/,拷贝 asm.jarcglib-2.1.3.jarTomcat/shared/lib
2.下载 c3p0最新版本 http://sourceforge.net/projects/c3p0,拷贝 c3p0-0.9.1.1.jarTomcat/shared/lib
3.下载 mysql-connector最新版本 http://sourceforge.net/projects/mmmysql/,拷贝 mysql-connector-java-5.0.4-bin.jarTomcat/shared/lib
4.下载 profile.v1.MySQL5.sql.rar解压缩为profile.v1.MySQL5.sql,导入到 MySQL数据库中。
  创建用户,用户名root,密码1

insert into T_PROFILE(USER_NAME, USER_PASSWORD) values('root', sha1('1'));

5.下载 sso.rar解压缩为sso.war,这个是登陆服务,复制到 Tomcat/webapps,下载 ssoagent.rar解压缩为ssoagent.war,这个是登陆代理,里面附带简单的业务逻辑,复制到 Tomcat/webapps,启动 tomcat,这时 Tomcat/webapps下面生成 ssossoagent两个目录,分别对应登陆服务和登陆代理,停止 tomcat
 
6.找到 Tomcat/webapps/sso/WEB-INF/classes/sso_passport.properties
 
      # 修改为你的实际的 /sso/passport/authen.jsp的路径。
      sso.passport.authenUrl=http://bsmith-cn:8080/sso/passport/authen.jsp
      # 修改为你的实际的 profile数据库的 url
      sso.passport.db.ds.c3p0.url=jdbc:mysql://localhost/profile
      # 修改为你的实际的 profile数据库用户名
      sso.passport.db.ds.c3p0.user=root
      # 修改为你的实际的 profile数据库密码
      sso.passport.db.ds.c3p0.password=1
 
7.    找到 Tomcat/webapps/ssoagent/WEB-INF/classes/sso_agent.properties
      # 修改为你的实际的 /sso/passport/login.srv路径
      sso.passport.login=http://bsmith-cn:8080/sso/passport/login.srv
      # 修改为你的实际的 /sso/passport/logout.srv路径
      sso.passport.logout=http://bsmith-cn:8080/sso/passport/logout.srv
 
8.      启动 Tomcat,输入 http://yourhost:yourport/ssoagent/logic/index.jsp测试,如果配置成功,将看到测试页面的几个业务逻辑,业务逻辑本身什么也不干,只是验证登陆有效性,有的业务逻辑需要登陆才能访问,有的不需要登陆就能访问。
 
 
文件:sso.rar
大小:30KB
下载:下载
文件:ssoagent.rar
大小:21KB
下载:下载
文件:profile.v1.MySQL5.sql.rar
大小:0KB
下载:下载
文件:sso.passport.src.v1.jar.rar
大小:56KB
下载:下载
文件:ssoagent.src.v1.jar.rar
大小:36KB
下载:下载
 
 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值