`
923723914
  • 浏览: 634948 次
文章分类
社区版块
存档分类
最新评论

CAS 之 集成RESTful API

 
阅读更多
最近因为公司另一款基于C/S的产品也需要整合到CAS 的 SSO,但是 CAS 本身对于客户端或浏览器而言是基于其COOKIE来存储用户(TGT)Ticket的,所以这时候就需要使用 CAS 的 RestFul API 来进行登录验证,并支持在C/S软件中点击用户头象时打开浏览器并跳转至用户中心,而且这时候在 WEB 上应该是已登录的状态(类似QQ点击自己的头象时,马上就进入到了QQ空间。)

关于CAS的登录验证流程,可以参考“CAS 之 实现用户注册后自动登录”,这里的RESTful登录验证流程与其大致相似,大体流程为:首先客户端提交用户名、密码、及Service三个参数,如果验证成功便返回用户的TGT(Ticket Granting Ticket)至客户端, 然后客户端再根据 TGT 获取用户的 ST(Service Ticket)来进行验证登录。 故名思意,TGT是用于生成一个新的Ticket(ST)的Ticket,而ST则是提供给客户端用于登录的Ticket,两者最大的区别在于,TGT是用户名密码验证成功之后所生成的Ticket,并且会保存在Server中及Cookie中,而ST则必须是是根据TGT来生成,主要用于登录,并且当登录成功之后 ST 则会失效。

CAS本身已经提供了 restlet 的集成包,如果你用的是 maven 的话直接加入,我这里的Cas-server的版本是 3.4.2.1:
Xml代码收藏代码
  1. <dependency>
  2. <groupId>org.jasig.cas</groupId>
  3. <artifactId>cas-server-integration-restlet</artifactId>
  4. <version>3.4.2.1</version>
  5. <type>jar</type>
  6. </dependency>

然后再在 web.xml 中加入:
Xml代码收藏代码
  1. <servlet>
  2. <servlet-name>restlet</servlet-name>
  3. <servlet-class>com.noelios.restlet.ext.spring.RestletFrameworkServlet</servlet-class>
  4. <load-on-startup>1</load-on-startup>
  5. </servlet>
  6. <servlet-mapping>
  7. <servlet-name>restlet</servlet-name>
  8. <url-pattern>/v1/*</url-pattern>
  9. </servlet-mapping>


因为使用到了 Restlat 框架,所以还需要依赖几个 jar 包,分别是:
  • com.noelios.restlet.ext.servlet.jar
  • com.noelios.restlet.ext.spring-1.1.0.jar
  • com.noelios.restlet.jar
  • org.restlet-1.1.10.jar
  • org.restlet.ext.spring-1.1.10.jar

这几个jar已经打包在附件中了,另外 restlet.org 的 maven库中也有,需要的话可以去maven.restlet.org上找。
另外关于 restlet的配置在 cas-server中已经存在在: /WEB-INF/restlet-servlet.xml文件。

配置OK之后直接启动Server,下面来进行简单登录验证的测试:

1. 提交用户名密码及Service 进行登录验证
Shell代码收藏代码
  1. DengerMacBook:cas-serverdenger$curl-i-XPOST-d"username=admin&password=123456&service=http://www.google.com"http://192.168.41.107:8080/member/v1/tickets/
  2. HTTP/1.1201Created
  3. Date:Wed,23Mar201112:42:52GMT
  4. Location:http://192.168.41.107:8080/member/v1/tickets/TGT-14-gDOn9hhSYmq3xfeTRNhTAjZgOMdCdyuVNfsuLRs6onNv7fVmmX-cas
  5. Accept-Ranges:bytes
  6. Server:Noelios-Restlet-Engine/1.1.6
  7. Content-Type:text/html;charset=ISO-8859-1
  8. Content-Length:437
  9. <!DOCTYPEHTMLPUBLIC"-//IETF//DTDHTML2.0//EN"><html><head><title>201Therequesthasbeenfulfilledandresultedinanewresourcebeingcreated</title></head><body><h1>TGTCreated</h1><formaction="http://192.168.41.107:8080/member/v1/tickets/TGT-14-gDOn9hhSYmq3xfeTRNhTAjZgOMdCdyuVNfsuLRs6onNv7fVmmX-cas"method="POST">Service:<inputtype="text"name="service"value=""><br><inputtype="submit"value="Submit"></form></body></html>

在以上Response信息及 Header中可以看到生成的 TGT,接下来是再重新根据 TGT 获取 ST,将请求的 URI 地址就是以上 Header中的 Location地址。

2. 根据返回的 TGT 来获取 ST
Shell代码收藏代码
  1. DengerMacBook:cas-serverdenger$curl-i-XPOST-d"service=http://www.google.com"http://192.168.41.107:8080/member/v1/tickets/TGT-14-gDOn9hhSYmq3xfeTRNhTAjZgOMdCdyuVNfsuLRs6onNv7fVmmX-cas
  2. HTTP/1.1200OK
  3. Date:Wed,23Mar201112:48:03GMT
  4. Accept-Ranges:bytes
  5. Server:Noelios-Restlet-Engine/1.1.6
  6. Content-Type:text/plain;charset=ISO-8859-1
  7. Content-Length:29
  8. ST-2-lJfQyJMMEnNGnKcglf1d-cas

获取成功之后则返回了 ST,这时候对于客户端而言就已经拿到了登录的TIcket, 如果需要在Web中自动登录的话,只需要弹出浏览器,将ST作为 ticket参数传入即可。如,用户中心的后台地址首页是:http://www.google.com.hk/userCenter 则URL为: http://www.google.com.hk/userCenter?ticket=ST-3-9QkpLsFmCEqIXSVvGH9P-cas 并可进行登录。 当然前提是在该Web应用中需要部署cas-client应用。

3. 注销用户
Shell代码收藏代码
  1. DengerMacBook:cas-serverdenger$curl-i-XDELETEhttp://192.168.41.107:8080/member/v1/tickets/TGT-14-gDOn9hhSYmq3xfeTRNhTAjZgOMdCdyuVNfsuLRs6onNv7fVmmX-cas
  2. HTTP/1.1200OK
  3. Date:Wed,23Mar201112:54:28GMT
  4. Accept-Ranges:bytes
  5. Server:Noelios-Restlet-Engine/1.1.6
  6. Content-Length:0
注销用户就很简单了,直接 SUBMIT DELETE 删除 TGT即可.

Java代码调用示例:
Java代码收藏代码
  1. packagecas;
  2. importjava.io.IOException;
  3. importjava.util.logging.Logger;
  4. importjava.util.regex.Matcher;
  5. importjava.util.regex.Pattern;
  6. importorg.apache.commons.httpclient.HttpClient;
  7. importorg.apache.commons.httpclient.NameValuePair;
  8. importorg.apache.commons.httpclient.methods.PostMethod;
  9. publicfinalclassClient
  10. {
  11. privatestaticfinalLoggerLOG=Logger.getLogger(Client.class.getName());
  12. privateClient()
  13. {
  14. //static-onlyaccess
  15. }
  16. publicstaticStringgetTicket(finalStringserver,finalStringusername,
  17. finalStringpassword,finalStringservice)
  18. {
  19. notNull(server,"servermustnotbenull");
  20. notNull(username,"usernamemustnotbenull");
  21. notNull(password,"passwordmustnotbenull");
  22. notNull(service,"servicemustnotbenull");
  23. returngetServiceTicket(server,getTicketGrantingTicket(server,username,
  24. password),service);
  25. }
  26. privatestaticStringgetServiceTicket(finalStringserver,
  27. finalStringticketGrantingTicket,finalStringservice)
  28. {
  29. if(ticketGrantingTicket==null)
  30. returnnull;
  31. finalHttpClientclient=newHttpClient();
  32. finalPostMethodpost=newPostMethod(server+"/"+ticketGrantingTicket);
  33. post.setRequestBody(newNameValuePair[]{newNameValuePair("service",
  34. service)});
  35. try
  36. {
  37. client.executeMethod(post);
  38. finalStringresponse=post.getResponseBodyAsString();
  39. switch(post.getStatusCode())
  40. {
  41. case200:
  42. returnresponse;
  43. default:
  44. LOG.warning("Invalidresponsecode("+post.getStatusCode()
  45. +")fromCASserver!");
  46. LOG.info("Response(1k):"
  47. +response.substring(0,Math.min(1024,response.length())));
  48. break;
  49. }
  50. }
  51. catch(finalIOExceptione)
  52. {
  53. LOG.warning(e.getMessage());
  54. }
  55. finally
  56. {
  57. post.releaseConnection();
  58. }
  59. returnnull;
  60. }
  61. privatestaticStringgetTicketGrantingTicket(finalStringserver,
  62. finalStringusername,finalStringpassword)
  63. {
  64. finalHttpClientclient=newHttpClient();
  65. finalPostMethodpost=newPostMethod(server);
  66. post.setRequestBody(newNameValuePair[]{
  67. newNameValuePair("username",username),
  68. newNameValuePair("password",password)});
  69. try
  70. {
  71. client.executeMethod(post);
  72. finalStringresponse=post.getResponseBodyAsString();
  73. switch(post.getStatusCode())
  74. {
  75. case201:
  76. {
  77. finalMatchermatcher=Pattern.compile(".*action=\".*/(.*?)\".*")
  78. .matcher(response);
  79. if(matcher.matches())
  80. returnmatcher.group(1);
  81. LOG
  82. .warning("Successfulticketgrantingrequest,butnoticketfound!");
  83. LOG.info("Response(1k):"
  84. +response.substring(0,Math.min(1024,response.length())));
  85. break;
  86. }
  87. default:
  88. LOG.warning("Invalidresponsecode("+post.getStatusCode()
  89. +")fromCASserver!");
  90. LOG.info("Response(1k):"
  91. +response.substring(0,Math.min(1024,response.length())));
  92. break;
  93. }
  94. }
  95. catch(finalIOExceptione)
  96. {
  97. LOG.warning(e.getMessage());
  98. }
  99. finally
  100. {
  101. post.releaseConnection();
  102. }
  103. returnnull;
  104. }
  105. privatestaticvoidnotNull(finalObjectobject,finalStringmessage)
  106. {
  107. if(object==null)
  108. thrownewIllegalArgumentException(message);
  109. }
  110. publicstaticvoidmain(finalString[]args)
  111. {
  112. finalStringserver="http://192.168.41.107:8080/member/v1/tickets";
  113. finalStringusername="admin";
  114. finalStringpassword="111111";
  115. finalStringservice="http://localhost:8080/service";
  116. LOG.info(getTicket(server,username,password,service));
  117. }
  118. }

参考:https://wiki.jasig.org/display/CASUM/RESTful+API
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics