CAS5.3单点登录REST协议登录操作说明

一、前言

CAS是一个旨在为应用系统提供单点登录方案的企业级的开源项目,它为第三方应用提供了基于REST的操作接口。

为后续表达准确,对相关术语作简单说明:

  • Web应用系统:准备集成CAS单点登录功能的各类Web应用;
  • CAS Server:本文中特指cas-server-webapp的war文件,需要独立部署,有时也称为认证系统、认证中心;
  • CAS Client:本文中特指cas-client-core-5.3.0.jar,需与应用系统一起部署。
  • CAS版本:除非特别声明,CAS各组件的版本均为5.3.0;
  • TGTTicket Grangting Ticket):TGTCAS为用户签发的登录票据,拥有了TGT,用户就可以证明自己在CAS成功登录过。TGT封装了Cookie值以及此Cookie值对应的用户信息。用户在CAS认证成功后,CAS生成cookie(叫TGC),写入浏览器,同时生成一个TGT对象,放入自己的缓存,TGT对象的ID就是cookie的值。当HTTP再次请求到来时,如果传过来的有CAS生成的cookie,则CAS以此cookie值为key查询缓存中有无TGT ,如果有的话,则说明用户之前登录过,如果没有,则用户需要重新登录;
  • STService Ticket):STCAS为用户签发的访问某一service的票据。用户访问service时,service发现用户没有ST,则要求用户去CAS获取ST。用户向CAS发出获取ST的请求,如果用户的请求中包含cookie,则CAS会以此cookie值为key查询缓存中有无TGT,如果存在TGT,则用此TGT签发一个ST,返回给用户。用户凭借ST去访问serviceserviceSTCAS验证,验证通过后,允许用户访问资源。

二、CAS REST协议接口说明

1、获取TGT

请求方式

POST

 

路径

localhost:8080/cas/v1/tickets

 

http协议

HTTP/1.0

 

请求参数

username=battags&password=password&additionalParam1=paramvalue

 

请求响应:

201 Created
Location:
localhost:8080/cas/v1/tickets/{TGT id}

 
 

2、获取ST

请求方式

POST

 

路径

localhost:8080/cas/v1/tickets/{TGT id}

 

http协议

HTTP/1.0

 

请求参数

service={form encoded parameter for the service url}

 

请求响应

200 OK
ST-1-FFDFHDSJKHSDFJKSDHFJKRUEYREWUIFSD2132

 
 

3、校验ST

请求方式

GET

路径

localhost:8080/cas/p3/serviceValidate

http协议

HTTP/1.0

请求参数

service={service url}&ticket={service ticket}

请求响应

状态码,200成功;200请求失败;415不支持的媒体类型;

4、登出

请求方式

DELETE

路径

http://172.25.51.1:8080/cas/v1/tickets/{TGT}

http协议

HTTP/1.0

请求响应

返回注销的TGT

 

三、示例代码(Java版本)

package cas_service;

 

import java.io.File;

import java.io.FileInputStream;

import java.io.IOException;

import java.net.URLEncoder;

import java.util.regex.Matcher;

import java.util.regex.Pattern;

 

import org.apache.commons.httpclient.HttpClient;

import org.apache.commons.httpclient.HttpStatus;

import org.apache.commons.httpclient.NameValuePair;

import org.apache.commons.httpclient.methods.DeleteMethod;

import org.apache.commons.httpclient.methods.GetMethod;

import org.apache.commons.httpclient.methods.PostMethod;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

 

...

 

public class CasService

{

    static private final Logger LOG = LoggerFactory.getLogger(CasService.class);

    private static String serverAddr;

    private static String serverPort;

    private static String serverConnString;

 

    static

    {

        String fileName = "cas-service.ini";

        try

        {

            ProjProperties props = newProjProperties();

            props.load(new FileInputStream(fileName));

            serverAddr = props.getProperty("SSO_SVR_ADDRESS", "localhost");

            serverPort = props.getProperty("SSO_SVR_PORT", "8443");

            serverConnString = "https://" + serverAddr + ":" + serverPort + "/cas";

        }

        catch (Exception e)

        {

            LOG.warn("load application server configuration ({}) failed. {}", fileName, e.getMessage());

        }

    }

 

    //获取TGT

    public String getTicketGrantingTicket(String username, String password)

    {

        if (serverConnString==null || serverConnString.equals(""))

            throw new Exception("Invalid parameter: CAS Server");

 

        HttpClient client = new HttpClient();

        PostMethod method = new PostMethod(serverConnString + "/v1/tickets");

 

        method.setRequestBody(new NameValuePair[]

        { new NameValuePair("username", username), new NameValuePair("password", password) });

 

        try

        {

            client.executeMethod(method);

            String response = method.getResponseBodyAsString();

 

            int status = method.getStatusCode();

            switch (status)

            {

            case HttpStatus.SC_CREATED: // Created

            {

                Matcher matcher = Pattern.compile(".*action=\".*/(.*?)\".*").matcher(response);

                if (matcher.matches())

                    return matcher.group(1);

                break;

            }

            default:

                throw new Exception("Invalid Response code " + status + " from CAS Server!");

            }

        }

        catch (IOException e)

        {

            LOG.error("some exception happened during apply for a TGT " + e.getMessage());

        }

        finally

        {

            method.releaseConnection();

        }

 

        return null;

    }

 

    //根据TGT获得ST

    public String getServiceTicket(String ticketGrantingTicket, String moduleName)

    {

        if (serverConnString==null || serverConnString.equals(""))

            throw new Exception("Invalid parameter: CAS Server");

        if (moduleName==null || moduleName.equals(""))

            throw new Exception("Invalid parameter: no module name within request.");

        if (ticketGrantingTicket==null || ticketGrantingTicket.equals(""))

            throw new Exception("Invalid TGT.");

 

        HttpClient client = new HttpClient();

        PostMethod method = new PostMethod(serverConnString + "/v1/tickets/" + ticketGrantingTicket);

 

        String service1 = buildModuleServiceName(moduleName);

        method.setRequestBody(new NameValuePair[]

        { new NameValuePair("service", service1) });

 

        try

        {

            client.executeMethod(method);

            String response = method.getResponseBodyAsString();

 

            int status = method.getStatusCode();

            switch (status)

            {

            case HttpStatus.SC_OK: // Accepted

                return response;

            default:

                throw new Exception("Invalid Response code " + status + " from CAS Server!");

            }

        }

        catch (IOException e)

        {

            LOG.error("some exception occured during apply for a service ticket. " + e.getMessage());

        }

        finally

        {

            method.releaseConnection();

        }

 

        return null;

    }

 

    //检验ST是否有效

    public String verifyServiceTicket(String serviceTicket, String moduleName)

    {

        if (serverConnString==null || serverConnString.equals(""))

            throw new Exception("Invalid parameter: CAS Server");

        if (moduleName==null || moduleName.equals(""))

            throw new Exception("Invalid parameter: module name");

 

        if (ABISHelper.isEmpty(serviceTicket))

            return null;

 

        HttpClient client = new HttpClient();

        GetMethod method = null;

        String service1 = buildModuleServiceName(moduleName);

        try

        {

            method = new GetMethod(serverConnString + "/p3/serviceValidate?ticket="

                    + URLEncoder.encode(serviceTicket, "utf-8") + "&service=" + URLEncoder.encode(service1, "utf-8"));

            client.executeMethod(method);

            String response = method.getResponseBodyAsString();

 

            // 对有转发的访问请求,GetMethod才返回SC_OK,PostMethod返回的是302

            int status = method.getStatusLine().getStatusCode();

            switch (status)

            {

            case HttpStatus.SC_OK: // Accepted

                int begin = response.indexOf("<cas:user>");

                if (begin < 0)

                    return null;

                int end = response.indexOf("</cas:user>");

                return response.substring(begin + 10, end);

            default:

                throw new Exception("Invalid Response code " + status + " from CAS Server!");

            }

        }

        catch (IOException e)

        {

            LOG.error("some exception occured during verify a service ticket. " + e.getMessage());

        }

        finally

        {

            method.releaseConnection();

        }

        return null;

    }

 

    //删除TGT

    public boolean deleteTicketGrantingTicket(String ticketGrantingTicket)

    {

        if (serverConnString==null || serverConnString.equals(""))

            throw new Exception("Invalid parameter: CAS Server");

 

        if (ticketGrantingTicket==null || ticketGrantingTicket.equals(""))

            return false;

 

        HttpClient client = new HttpClient();

        DeleteMethod method = new DeleteMethod(serverConnString + "/v1/tickets/" + ticketGrantingTicket);

 

        try

        {

            client.executeMethod(method);

            int status = method.getStatusCode();

            switch (status)

            {

            case HttpStatus.SC_OK:

                return true;

            default:

                throw new Exception("Invalid Response code " + status + " from CAS Server!");

            }

        }

        catch (IOException e)

        {

            LOG.error("some exception occured during verifing a service ticket" + e.getMessage());

        }

        finally

        {

            method.releaseConnection();

        }

        return false;

    }

 

    private String buildModuleServiceName(String moduleName)

    {

        return "https://" + serverAddr + ":" + serverPort + "/" + moduleName;

}

public String getCasUserName ()

    {

        return SessionUtils. getAttribute("_COST_CAS_USER_NAME");

}

 

 

}

 

四、典型的调用流程

以下是应用系统使用cas_service包接口的典型流程:

  •  某用户登录应用A,因为是首次登录,需提供用户名、密码;
  •  应用A根据用户名、密码,调用getTicketGrantingTicket接口获取TGT;
  •  TGT多次使用,需保存在session或其它存储对象中;
  •  应用A使用TGT,调用getServiceTicket接口获取am服务的ST;
  •  应用A可使用刚获取的ST,作为参数访问am服务;
  •  ST因有效期短暂且使用次数有限制,一般是一次性使用,不必保存;
  •  用户欲访问应用B的bn服务,先从session或其它存储对象中查找到TGT;
  •  应用A(或应用B)TGT,调用getServiceTicket接口获取bn服务的ST;
  •  应用B接收ST,调用verifySeviceTicket接口,返回不为null则该ST有效;
  •  验证通过后,应用B使用该ST访问bn服务;
  •  应用B可调用接口getCasUserName和getCasAttributes,获取登录用户及相关属性;
  •  欲根据ST查找当前登录用户,调用getUsernameSeviceTicket接口,返回值即是;
  •  用户从某应用注销时,需调用deleteTicketGrantingTicket接口从Cas Server删除TGT。
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值