SSO在我们的应用中非常常见,例如我们在OA系统登录了,我们就可以直接进入采购系统,不需要再登录了,这样使我们非常方便。现在网上也有很多实现方法,于是乎我也想写一个看看。我主要用到的是cookie的机制。在此,分享给大家,同时提供源代码下载。
进入主题:
工程说明
SSO的实现一般是会有一个SSO Server,也会叫认证中心,同时也会有被认证的系统,如OA系统、采购系统等,他们就相当于SSO Server的client。
为了更形象体现SSO,我写的SSO是有三个工程:一个SSO Server端口为8081,一个OA系统端口为8082,一个采购系统端口为8083。如图:
流程介绍
在整个SSO流程当,有两个流程非常重要,第一个是用户没有登录系统到登录系统的过程;第二是用户在一个系统当中已经登录(例如在OA系统中登录 了),但又想进入另一个系统(例如进入PRO系统)的过程,如果把这两个过程搞定了,那么SSO也就搞定了。我画了两幅图来说明这两个过程。
先看用户没有登录系统到登录系统的过程,如图:
1:用户通过URL访问OA系统。
2:在OA系统中的filter发现这个URL没有ticket(你暂且就把ticket看做是门票),此时就会跳转到SSO Server。
3:SSO Server中的filter发现该客户端中的cookie中没有相应信息,也即是一个没有登录的用户,那么会跳转到登录页面。
4:用户在登录页面填写相应信息,然后通过post方式提交到SSO Server中。
5:SSO Server会校验用户信息(我为了快,我的校验方式就是要用户名为:cloud,同时密码为:cloud),同时在cookie中放username。
6:将生成ticket和username放到JVMCache中,在实际项目应该放到Memcached中,它的用处等下分析。
7,8:就是在用户访问OA系统的URL基础上加上了一个ticket参数,这样跳转到OA系统。
(此时进入OA系统时,filter发现URL是带ticket的,则filter会根据带过来的ticket并通过HttpClient的形式去调用SSO Server中的TicektServlet,这样就会返回用户名,其实这个用户名就是从JVMCache拿到的,同时马上将这个ticket从JVMCache中移除,这样保证一个ticket只会用一次,然后把返回的用户名放到session中)
9:session中有了用户名,说明用户登录成功了,则会去本应该返问的servlet。
10,11:将OA系统返回的视图给用户。
第二过程,用户已经登录成功了,但要访问另一个系统,如图:
1:用户通过URL访问PRO系统。
2:在PRO系统中的filter发现这个URL没有ticket,此时就会跳转到SSO Server。此时,由于用户登录了,所以cookie中有相应的信息(例如用户名),此时SSO Server中的filter会生成一个ticket。
3:将生成的ticket和username放到JVMCache中。
4:就是在用户访问PRO系统的URL基础上加上了一个ticket参数,这样跳转到PRO系统。
(此时进入PRO系统时,filter发现URL是带ticket的,则filter会根据带过来的ticket并通过HttpClient的形式去调用SSO Server中的TicektServlet,这样就会返回用户名,其实这个用户名就是从JVMCache拿到的,同时马上将这个ticket从JVMCache中移除,这样保证一个ticket只会用一次,然后把返回的用户名放到session中)
5:session中有了用户名,说明用户登录成功了,则会去本应该返问的servlet。
5,7:将PRO系统返回的视图给用户。
关键代码
先看SSO Server工程中的代码:
pom.xml
(注意:端口为8081)
4.0.0com.cloud.sso.serversso-serverwar0.0.1-SNAPSHOTsso-server Maven Webapphttp://maven.apache.orgjavax.servletservlet-api2.5providedsso-serverorg.mortbay.jettyjetty-maven-plugin8.1.9.v20130131stop6000/sso4808160000
SSO Server中的filter
SSOServerFilter.java
package com.cloud.sso.server.filter; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.cloud.sso.server.JVMCache; public class SSOServerFilter imple