转载:http://blog.csdn.net/xqhys/article/details/63920161?locationNum=3&fps=1
一、什么是单点登录SSO(Single Sign-On)
SSO是一种统一认证和授权机制,指访问同一服务器不同应用中的受保护资源的同一用户,只需要登录一次,即通过一个应用中的安全验证后,再访问其他应用中的受保护资源时,不再需要重新登录验证。
二、单点登录解决了什么问题
解决了用户只需要登录一次就可以访问所有相互信任的应用系统,而不用重复登录。
工程说明
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会校验用户信息(我为了快,我的校验方式就是要用户名为:admin,同时密码为:1111),同时在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)
- <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <groupId>com.cloud.sso.server</groupId>
- <artifactId>sso-server</artifactId>
- <packaging>war</packaging>
- <version>0.0.1-SNAPSHOT</version>
- <name>sso-server Maven Webapp</name>
- <url>http://maven.apache.org</url>
- <dependencies>
- <dependency>
- <groupId>javax.servlet</groupId>
- <artifactId>servlet-api</artifactId>
- <version>2.5</version>
- <scope>provided</scope>
- </dependency>
- </dependencies>
- <build>
- <finalName>sso-server</finalName>
- <plugins>
- <plugin>
- <groupId>org.mortbay.jetty</groupId>
- <artifactId>jetty-maven-plugin</artifactId>
- <version>8.1.9.v20130131</version>
- <configuration>
- <!-- 配置jetty的容器 端口等 -->
- <connectors>
- <connector implementation="org.eclipse.jetty.server.nio.SelectChannelConnector">
- <port>8081</port>
- <maxIdleTime>30000</maxIdleTime>
- </connector>
- </connectors>
- <!-- 添加一个特殊的端口和控制键(mvn jetty:stop 停止jetty服务) -->
- <stopKey>stop</stopKey>
- <stopPort>9977</stopPort>
- <!-- 发现内容改变,进行热部署,默认是0,不热部署 -->
- <scanIntervalSeconds>1</scanIntervalSeconds>
- <!-- 配置web容器 -->
- <webAppSourceDirectory>src/main/webapp</webAppSourceDirectory>
- <webAppConfig>
- <!-- 项目的根目录,默认是"/" -->
- <contextPath>/sso-server</contextPath>
- <!-- <descriptor></descriptor> --> <!-- The path to the web.xml file for your webapp -->
- <!-- <defaultsDescriptor>src/main/resources/webdefault.xml</defaultsDescriptor>
- webdefault.xml的路径,若没有配置就是用jetty默认,这个文件在web.xml加载之前加载 -->
- </webAppConfig>
- <!-- 自动部署默认是 automatic -->
- <reload>automatic</reload>
- <systemProperties>
- <systemProperty>
- <name>org.mortbay.util.URI.charset</name>
- <value>UTF-8</value>
- </systemProperty>
- </systemProperties>
- </configuration>
- </plugin>
- </plugins>
- </build>
- </project>
SSO Server中的filter
- package com.cloud.sso.server.filter;
- import java.io.IOException;
- import javax.servlet.Filter;
- import javax.servlet.FilterChain;