您的位置:首页 > 其它

SSO实现方案

2014-06-03 10:12 197 查看
一、单点登录介绍

单点登录的机制比较简单,如下图所示:





1、当用户第一次访问应用系统的时候,因为用户还没有登录,应用系统会向认证系统请求ticket。
2、认证系统接收到ticket的请求,如果用户已经登录则返回ticket,进行第4步操作,如果用户还没有登录,则引导到认证系统的登录页面。
3、用户提交用户名密码,认证系统进行身份效验,如果通过效验,应该返回给用户一个认证的凭据(ticket)到应用系统
4、应用系统接收到ticket,向认证系统发起验证ticket的请求
5、认证系统通过ticket的验证,并删除掉保存在认证系统的ticket,然后返回用户信息
6、应用系统接收到返回的用户信息,然后通过本地认证,返回受保护资源给用户

二、认证系统的实现
在认证系统中接入应用系统。

Java

1234private static Map<String, String> clientMap = new HashMap<String, String>();static{ clientMap.put("1000" , "client1000" );}
认证系统的登录认证,如果只是登录到认证系统,则进去认证系统的首页,如果请求中包含appId和callback参数的,则说明是应用系统的登录请求,则需要返回到应用系统,并且返回ticket。generateTicket()是生成ticket的,一般是一串加密串,我这里为了简单起见直接使用UUID。注:这里还返回了sessionId,因为下面的应用系统请求验证ticket的时候,使用的HttpClient,发送的是http请求,没有sessionId,则读取不到认证系统中的session。Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

@RequestMapping("loginAuth.htm")

publicvoidloginAuth(HttpServletRequestrequest,HttpServletResponseresponse,StringuserId)throwsIOException{

request.getSession().setAttribute("userId",userId);

request.getSession().setAttribute("ticketMap",newHashMap<String,String>());

Stringcallback=request.getParameter("callback");

StringappId=request.getParameter("appId");

//如果是应用系统过来的登录验证,需要返回ticket

if(StringUtils.hasText(callback)&&StringUtils.hasText(appId)){

Stringticket=generateTicket(appId,request);

Stringurl=callback+"?ticket="+ticket;

StringsessionParam=getSessionId(request);

if(StringUtils.hasText(sessionParam)){

url+="&"+sessionParam;

}

response.sendRedirect(url);

}else{

response.sendRedirect("/server/admin.htm");

}

}

认证系统接收应用系统的验证ticket请求,并返回登录用户的信息

Java

1234567891011121314151617181920212223242526272829303132@ResponseBody@RequestMapping("validTicket.htm" )public Object validTicket(HttpServletRequest request,HttpServletResponse response){ String appId = request.getParameter( "appId"); String ticket = request.getParameter( "ticket"); String secret = request.getParameter( "secret"); ValidReturn result = new ValidReturn(); if(clientMap .containsKey(appId)){ //验证第三方系统的是否存在 String appSecret = clientMap.get(appId); if(appSecret.equals(secret)){ //验证第三方系统的密码 Map<String, String> ticketMap = (HashMap<String, String>)request.getSession().getAttribute("ticketMap" ); if(ticketMap.containsKey(appId)){ String existTicket = ticketMap.get(appId); if(existTicket.equals(ticket)){ String userId = (String)request.getSession().getAttribute("userId" ); result.setUserId(userId); ticketMap.remove(appId); // 验证之后删除ticket } else{ result.setError( "ticket error"); } } else{ result.setError( "ticket expired"); } } else{ result.setError( "password error"); } } else{ result.setError( "app not exist"); } return result;}
三、应用系统实现[align=left] 用户访问应用系统的受保护资源,如果用户还未在本应用系统登录过,应用系统会向认证系统发起获取ticket的请求[/align][align=left][/align]Java

1

2

3

4

5

6

7

8

9

10

11

12

13

@RequestMapping("admin.htm")

publicStringadmin(HttpServletRequestrequest,HttpServletResponseresponse){

StringuserId=(String)request.getSession().getAttribute("userId");

if(StringUtils.hasText(userId)){

return"client/admin";

}

try{

response.sendRedirect("http://www.server.com:8080/server/getTicket.htm?appId=1000&callback=http://www.client.com:8081/client/callback.htm");

}catch(IOExceptione){

e.printStackTrace();

}

returnnull;

}

应用系统接收到认证系统返回的ticket,然后发起验证ticket的请求

Java

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")

publicvoidcallback(HttpServletRequestrequest,HttpServletResponseresponse)throwsIOException{

Stringerror=request.getParameter("error");

if(StringUtils.hasText(error)){

System.out.println(error);

response.sendRedirect("/client/error.htm?error="+error);

}else{

Stringticket=request.getParameter("ticket");//获取ticket

StringsessionId=request.getParameter("JSESSIONID");//获取
sessionid

ValidReturnresult=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(Exceptione){

e.printStackTrace();

}

if(result==null){

response.sendRedirect("/client/error.htm?error=0000000");

}

}

}

privateValidReturnvalidAndGetUserId(Stringticket,StringsessionId)throwsHttpException,IOException{

//如何获取session,获取cookies

PostMethodpostMethod=newPostMethod("http://www.server.com:8080/server/validTicket.htm");

postMethod.addParameter("appId","1000");

postMethod.addParameter("secret","client1000");

postMethod.addParameter("ticket",ticket);

//postMethod.addParameter("JSESSIONID",seesionId);

HttpMethodParamsparam=postMethod.getParams();

param.setContentCharset("UTF-8");

postMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,

newDefaultHttpMethodRetryHandler(3,false));

postMethod.setRequestHeader("Cookie","JSESSIONID="+sessionId);//添加sessionId,让Server知道使用哪个Session

HttpClientParamsclientParams=newHttpClientParams();

//
忽略cookie 避免 Cookie rejected 警告

clientParams.setCookiePolicy(CookiePolicy.IGNORE_COOKIES);

HttpClientclient=newHttpClient(clientParams);

client.executeMethod(postMethod);

Header[]resHeader=postMethod.getResponseHeaders();

intresponseCode=postMethod.getStatusCode();

System.out.println("responseCode:"+responseCode);

for(Headerheader:resHeader){

System.out.println(header.getName()+":"+header.getValue());

}

StringreturnStr=postMethod.getResponseBodyAsString();

ValidReturnresult=newGson().fromJson(returnStr,ValidReturn.class);

postMethod.releaseConnection();

returnresult;

}

四、示例下载及运行说明

示例下载地址:http://download.csdn.net/download/yangpingzhun/5476937

示例程序需要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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: