最近因为公司另一款基于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:
- <dependency>
- <groupId>org.jasig.cas</groupId>
- <artifactId>cas-server-integration-restlet</artifactId>
- <version>3.4.2.1</version>
- <type>jar</type>
- </dependency>
然后再在 web.xml 中加入:
- <servlet>
- <servlet-name>restlet</servlet-name>
- <servlet-class>com.noelios.restlet.ext.spring.RestletFrameworkServlet</servlet-class>
- <load-on-startup>1</load-on-startup>
- </servlet>
- <servlet-mapping>
- <servlet-name>restlet</servlet-name>
- <url-pattern>/v1/*</url-pattern>
- </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 进行登录验证
- 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/
- HTTP/1.1201Created
- Date:Wed,23Mar201112:42:52GMT
- Location:http://192.168.41.107:8080/member/v1/tickets/TGT-14-gDOn9hhSYmq3xfeTRNhTAjZgOMdCdyuVNfsuLRs6onNv7fVmmX-cas
- Accept-Ranges:bytes
- Server:Noelios-Restlet-Engine/1.1.6
- Content-Type:text/html;charset=ISO-8859-1
- Content-Length:437
- <!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
- 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
- HTTP/1.1200OK
- Date:Wed,23Mar201112:48:03GMT
- Accept-Ranges:bytes
- Server:Noelios-Restlet-Engine/1.1.6
- Content-Type:text/plain;charset=ISO-8859-1
- Content-Length:29
- 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. 注销用户
- DengerMacBook:cas-serverdenger$curl-i-XDELETEhttp://192.168.41.107:8080/member/v1/tickets/TGT-14-gDOn9hhSYmq3xfeTRNhTAjZgOMdCdyuVNfsuLRs6onNv7fVmmX-cas
- HTTP/1.1200OK
- Date:Wed,23Mar201112:54:28GMT
- Accept-Ranges:bytes
- Server:Noelios-Restlet-Engine/1.1.6
- Content-Length:0
注销用户就很简单了,直接 SUBMIT DELETE 删除 TGT即可.
Java代码调用示例:
- packagecas;
- importjava.io.IOException;
- importjava.util.logging.Logger;
- importjava.util.regex.Matcher;
- importjava.util.regex.Pattern;
- importorg.apache.commons.httpclient.HttpClient;
- importorg.apache.commons.httpclient.NameValuePair;
- importorg.apache.commons.httpclient.methods.PostMethod;
- publicfinalclassClient
- {
- privatestaticfinalLoggerLOG=Logger.getLogger(Client.class.getName());
- privateClient()
- {
- }
- publicstaticStringgetTicket(finalStringserver,finalStringusername,
- finalStringpassword,finalStringservice)
- {
- notNull(server,"servermustnotbenull");
- notNull(username,"usernamemustnotbenull");
- notNull(password,"passwordmustnotbenull");
- notNull(service,"servicemustnotbenull");
- returngetServiceTicket(server,getTicketGrantingTicket(server,username,
- password),service);
- }
- privatestaticStringgetServiceTicket(finalStringserver,
- finalStringticketGrantingTicket,finalStringservice)
- {
- if(ticketGrantingTicket==null)
- returnnull;
- finalHttpClientclient=newHttpClient();
- finalPostMethodpost=newPostMethod(server+"/"+ticketGrantingTicket);
- post.setRequestBody(newNameValuePair[]{newNameValuePair("service",
- service)});
- try
- {
- client.executeMethod(post);
- finalStringresponse=post.getResponseBodyAsString();
- switch(post.getStatusCode())
- {
- case200:
- returnresponse;
- default:
- LOG.warning("Invalidresponsecode("+post.getStatusCode()
- +")fromCASserver!");
- LOG.info("Response(1k):"
- +response.substring(0,Math.min(1024,response.length())));
- break;
- }
- }
- catch(finalIOExceptione)
- {
- LOG.warning(e.getMessage());
- }
- finally
- {
- post.releaseConnection();
- }
- returnnull;
- }
- privatestaticStringgetTicketGrantingTicket(finalStringserver,
- finalStringusername,finalStringpassword)
- {
- finalHttpClientclient=newHttpClient();
- finalPostMethodpost=newPostMethod(server);
- post.setRequestBody(newNameValuePair[]{
- newNameValuePair("username",username),
- newNameValuePair("password",password)});
- try
- {
- client.executeMethod(post);
- finalStringresponse=post.getResponseBodyAsString();
- switch(post.getStatusCode())
- {
- case201:
- {
- finalMatchermatcher=Pattern.compile(".*action=\".*/(.*?)\".*")
- .matcher(response);
- if(matcher.matches())
- returnmatcher.group(1);
- LOG
- .warning("Successfulticketgrantingrequest,butnoticketfound!");
- LOG.info("Response(1k):"
- +response.substring(0,Math.min(1024,response.length())));
- break;
- }
- default:
- LOG.warning("Invalidresponsecode("+post.getStatusCode()
- +")fromCASserver!");
- LOG.info("Response(1k):"
- +response.substring(0,Math.min(1024,response.length())));
- break;
- }
- }
- catch(finalIOExceptione)
- {
- LOG.warning(e.getMessage());
- }
- finally
- {
- post.releaseConnection();
- }
- returnnull;
- }
- privatestaticvoidnotNull(finalObjectobject,finalStringmessage)
- {
- if(object==null)
- thrownewIllegalArgumentException(message);
- }
- publicstaticvoidmain(finalString[]args)
- {
- finalStringserver="http://192.168.41.107:8080/member/v1/tickets";
- finalStringusername="admin";
- finalStringpassword="111111";
- finalStringservice="http://localhost:8080/service";
- LOG.info(getTicket(server,username,password,service));
- }
- }
参考:
https://wiki.jasig.org/display/CASUM/RESTful+API
分享到:
相关推荐
n cas-server-3.4.2\modules\cas-server-support-jdbc-3.4.2.jar 、 cas-server-integration-restlet-3.4.2.jar 拷贝到 D:\server\apache-tomcat-6.0.18\webapps\cas\WEB-INF\lib 目录下。 n 数据库驱动 jar 拷贝...
Python Flask高级编程之RESTFul API前后端分离精讲Python Flask高级编程之RESTFul API前后端分离精讲Python Flask高级编程之RESTFul API前后端分离精讲Python Flask高级编程之RESTFul API前后端分离精讲Python Flask...
Python Flask高级编程之RESTFul API前后端分离精讲第六章节Python Flask高级编程之RESTFul API前后端分离精讲第六章节Python Flask高级编程之RESTFul API前后端分离精讲第六章节Python Flask高级编程之RESTFul API...
Python Flask高级编程之RESTFul API前后端分离精讲第二章节Python Flask高级编程之RESTFul API前后端分离精讲第二章节Python Flask高级编程之RESTFul API前后端分离精讲第二章节Python Flask高级编程之RESTFul API...
thinkphp6 RESTful API开发 开发过程记录笔记 https://blog.csdn.net/weixin_41120504/article/details/115638094
restful api 接口说明. 总结 restful api 语法知识和常用的状态码含义.
RESTful API设计规范.pdf
此代码通过c c++实现一个简单的http服务,可以用此实现一个restful api 服务器.
Python Flask高级编程之RESTFul API前后端分离精讲第五章节Python Flask高级编程之RESTFul API前后端分离精讲第五章节Python Flask高级编程之RESTFul API前后端分离精讲第五章节Python Flask高级编程之RESTFul API...
Python Flask高级编程之RESTFul API前后端分离精讲第四章节Python Flask高级编程之RESTFul API前后端分离精讲第四章节Python Flask高级编程之RESTFul API前后端分离精讲第四章节Python Flask高级编程之RESTFul API...
Python Flask高级编程之RESTFul API前后端分离精讲第三章节Python Flask高级编程之RESTFul API前后端分离精讲第三章节Python Flask高级编程之RESTFul API前后端分离精讲第三章节Python Flask高级编程之RESTFul API...
Python Flask高级编程之RESTFul API前后端分离精讲第六章节Python Flask高级编程之RESTFul API前后端分离精讲第六章节Python Flask高级编程之RESTFul API前后端分离精讲第六章节Python Flask高级编程之RESTFul API...
Python Flask高级编程之RESTFul API前后端分离精讲第九章节Python Flask高级编程之RESTFul API前后端分离精讲第九章节Python Flask高级编程之RESTFul API前后端分离精讲第九章节Python Flask高级编程之RESTFul API...
springboot入门demo...实现了restful api和webservice两种接口方式。(可通过postman或soupui进行测试。) 同时包含了Junit测试webservice。 Demo是经过亲测完全可以跑起来。通过此demo可对springboot有个入门的理解
RESTful API设计规范
Python Flask高级编程之RESTFul API前后端分离精讲第八章节(2)Python Flask高级编程之RESTFul API前后端分离精讲第八章节(2)Python Flask高级编程之RESTFul API前后端分离精讲第八章节(2)Python Flask高级编程...
Python Flask高级编程之RESTFul API前后端分离精讲第八章节(1)Python Flask高级编程之RESTFul API前后端分离精讲第八章节(1)Python Flask高级编程之RESTFul API前后端分离精讲第八章节(1)Python Flask高级编程...
restful api访问k8s集群,增删改查信息。 需要预先创建访问权限的配置。 官网api文档 https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.9/ 下面罗列部分api curl -u admin:admin ...
SpringBoot+Mybatis+CXF框架,实现Restful api与 WebService api接口的大实验
Spring boot restful api demo