一、单点登录介绍
单点登录的机制比较简单,如下图所示:
1、当用户第一次访问应用系统的时候,因为用户还没有登录,应用系统会向认证系统请求ticket。
2、认证系统接收到ticket的请求,如果用户已经登录则返回ticket,进行第4步操作,如果用户还没有登录,则引导到认证系统的登录页面。
3、用户提交用户名密码,认证系统进行身份效验,如果通过效验,应该返回给用户一个认证的凭据(ticket)到应用系统
4、应用系统接收到ticket,向认证系统发起验证ticket的请求
5、认证系统通过ticket的验证,并删除掉保存在认证系统的ticket,然后返回用户信息
6、应用系统接收到返回的用户信息,然后通过本地认证,返回受保护资源给用户
二、认证系统的实现
在认证系统中接入应用系统。
认证系统的登录认证,如果只是登录到认证系统,则进去认证系统的首页,如果请求中包含appId和callback参数的,则说明是应用系统的登录请求,则需要返回到应用系统,并且返回ticket。generateTicket()是生成ticket的,一般是一串加密串,我这里为了简单起见直接使用UUID。注:这里还返回了sessionId,因为下面的应用系统请求验证ticket的时候,使用的HttpClient,发送的是http请求,没有sessionId,则读取不到认证系统中的session。
认证系统接收应用系统的验证ticket请求,并返回登录用户的信息
三、应用系统实现
用户访问应用系统的受保护资源,如果用户还未在本应用系统登录过,应用系统会向认证系统发起获取ticket的请求
应用系统接收到认证系统返回的ticket,然后发起验证ticket的请求
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
@RequestMapping
(
"callback.htm"
)
public
void
callback
(
HttpServletRequest
request
,
HttpServletResponse
response
)
throws
IOException
{
String
error
=
request
.
getParameter
(
"error"
)
;
if
(
StringUtils
.
hasText
(
error
)
)
{
System
.
out
.
println
(
error
)
;
response
.
sendRedirect
(
"/client/error.htm?error="
+
error
)
;
}
else
{
String
ticket
=
request
.
getParameter
(
"ticket"
)
;
//获取ticket
String
sessionId
=
request
.
getParameter
(
"JSESSIONID"
)
;
//获取 sessionid
ValidReturn
result
=
null
;
try
{
result
=
validAndGetUserId
(
ticket
,
sessionId
)
;
if
(
StringUtils
.
hasText
(
result
.
getUserId
(
)
)
)
{
request
.
getSession
(
)
.
setAttribute
(
"userId"
,
result
.
getUserId
(
)
)
;
response
.
sendRedirect
(
"/client/admin.htm"
)
;
}
else
{
response
.
sendRedirect
(
"/client/error.htm?error="
+
result
.
getError
(
)
)
;
}
}
catch
(
Exception
e
)
{
e
.
printStackTrace
(
)
;
}
if
(
result
==
null
)
{
response
.
sendRedirect
(
"/client/error.htm?error=0000000"
)
;
}
}
}
private
ValidReturn
validAndGetUserId
(
String
ticket
,
String
sessionId
)
throws
HttpException
,
IOException
{
//如何获取session,获取cookies
PostMethod
postMethod
=
new
PostMethod
(
"http://www.server.com:8080/server/validTicket.htm"
)
;
postMethod
.
addParameter
(
"appId"
,
"1000"
)
;
postMethod
.
addParameter
(
"secret"
,
"client1000"
)
;
postMethod
.
addParameter
(
"ticket"
,
ticket
)
;
//postMethod.addParameter("JSESSIONID",seesionId);
HttpMethodParams
param
=
postMethod
.
getParams
(
)
;
param
.
setContentCharset
(
"UTF-8"
)
;
postMethod
.
getParams
(
)
.
setParameter
(
HttpMethodParams
.
RETRY_HANDLER
,
new
DefaultHttpMethodRetryHandler
(
3
,
false
)
)
;
postMethod
.
setRequestHeader
(
"Cookie"
,
"JSESSIONID="
+
sessionId
)
;
//添加sessionId,让Server知道使用哪个Session
HttpClientParams
clientParams
=
new
HttpClientParams
(
)
;
// 忽略cookie 避免 Cookie rejected 警告
clientParams
.
setCookiePolicy
(
CookiePolicy
.
IGNORE_COOKIES
)
;
HttpClient
client
=
new
HttpClient
(
clientParams
)
;
client
.
executeMethod
(
postMethod
)
;
Header
[
]
resHeader
=
postMethod
.
getResponseHeaders
(
)
;
int
responseCode
=
postMethod
.
getStatusCode
(
)
;
System
.
out
.
println
(
"responseCode:"
+
responseCode
)
;
for
(
Header
header
:
resHeader
)
{
System
.
out
.
println
(
header
.
getName
(
)
+
":"
+
header
.
getValue
(
)
)
;
}
String
returnStr
=
postMethod
.
getResponseBodyAsString
(
)
;
ValidReturn
result
=
new
Gson
(
)
.
fromJson
(
returnStr
,
ValidReturn
.
class
)
;
postMethod
.
releaseConnection
(
)
;
return
result
;
}
|
四、示例下载及运行说明
示例程序需要maven支持,所以需要运行的示例的,需要安装maven;在hosts文件中配置一条域名解析(127.0.0.1 www.server.com www.client.com),然后运行test源文件夹下的JettyServer和JettyClient即可,测试url:http://www.client.com:8081/client/admin.htm