概述:
由携程商旅(以下简称“携程”)向客户提供的单点登录对接服务。该服务采用Restful的方式实现。本文档中包含接口方法说明、设计文档、调用方法及完整示例代码。单点登录支持跳转方式,不建议采用嵌套方式,因为嵌套方式IE有不支持的情况。
注意事项:
1、特别提醒:接口调用务必采用域名方式调用,切勿采用IP地址方式调用。
2、接口调用顺序,先调用获取Ticket服务,再调用单点登录服务。
3、因安全传输协议要求,该接口不支持Windows XP系统的IE内核浏览器。
4、因HTTP存在安全隐患,必须采用HTTPS方式调用。
5、Iframe嵌套方式可能会导致预订站点部分功能不可用,请慎用。
1.描述
客户公司需事先提供员工相关信息给携程, 携程为每一个员工指定一个携程卡号并与其员工工号关联,同时为该公司提供单点登录接口的接入账号和接入密码。
当员工通过其内部系统(如:OA系统)访问携程网站时,内部系统根据当前员工信息提供员工工号或携程卡号、接入账号、接入密码等接入携程单点登录系统。携程单点登录系统自动校验接入账号和接入密码,并与携程商旅管理系统内置的员工信息匹配,实现员工身份的识别和整合登录。
2.接口方法说明
2.1.获取Ticket
调用地址: | https://ct.ctrip.com/corpservice/authorize/getticket |
调用方式: | https + post |
方法名: | GetTicket |
描述: | 根据已设定的公司接入账户和公司接入密码获得登录令牌。在调用单点登陆服务前,必须要先获取令牌,通过令牌进行登陆。申请令牌时的客户接入账户必须与登陆时的接入账户是一致的。令牌的只能使用一次,登陆后不管成功与否,令牌都会失效,需要重新申请令牌方可再次登陆。 |
参数: | 实体TicketModel实例化对象 |
参数类型: | 对象类型 |
2.2.单点登录Login
调用地址: | https://ct.ctrip.com/corpservice/authorize/login |
调用方式: | https + post(必须使用提交Form表单方式调用,具体请参考4.1.4) |
方法名: | Login |
描述: | 根据登录令牌进行单点登录,并传递相关预订信息到携程企业商旅预订站点。获取到令牌后,通过当前服务进行登陆验证。客户公司用户的身份校验合法,则会登陆到指定的页面,如果身份校验失败则会返回对应的错误信息,错误信息参考下面2.3 |
参数: | Form表单 |
参数类型: | 表单参数 |
3.接口契约说明
3.1. 获取Ticket
3.1.1.请求契约
TicketModel | |||||
字段 | 类型 | 描述 | 默认值 | 可为空 | 备注 |
AppKey | String | 接入账号,携程分配给客户公司 | N | ||
AppSecurity | String | 接入密码,携程分配给客户公司 | N | ||
TokenType | Int | 获取token类型 | 0 | Y | 包括两个枚举值:0,1,2 0:代表不自动开卡 1:大客户需要自动开卡 2:平台客户需要自动开卡 |
GroupID | Int | 卡号分组,需要携程提供 | Y | 仅当TokenType为1时,必须传送该值 |
3.1.2.返回契约
在返回值的Json数据中,客户公司根据自动进行转换实体,建议不要使用绝对匹配属性,避免携程添加属性契约进行升级时造成转换失败引起功能不可用。
返回Json数据 | ||||
字段 | 类型 | 描述 | 可为空 | 备注 |
Token | String | 单点登录令牌 | N | |
Code | Int | 参数验证是否成功 | N | 0 成功;1 参数验证失败;2.接口异常 |
Message | String | Result不为Success时给出具体错误信息 | N | 在系统已知的错误中包含了对应的Code,请参考下面2.3 |
Success | Boolean | 是否接口调用成功 | N | 成功:true 失败:false |
示例: {"Token":"56a0af18ae30a168d4006c7c","Message":"","Code":0,"Success":true}
3.2. 单点登录Login
3.2.1.请求契约
登陆成功后,默认会登陆到商旅页面的首页,如果客户需要指定跳转页面,则在Backurl属性中传递对应的路径或使用SearchType字段实现跳转到查询结果页面。
SSOLoginModel | |||||
字段 | 类型 | 描述 | 默认值 | 可为空 | 备注 |
AppKey | String | 接入账号,携程分配给客户公司 | N | ||
Ticket | String | 登录请求令牌 | N | 请见2.1 | |
UID | String | 客户公司员工携程卡号 | Y | 携程卡号和员工工号至少提供一个 | |
EmployeeID | String | 客户公司员工工号 | Y | 长度限制varchar(100) | |
Signature | String | MD5签名,长度为32 | N | 签名生成规则说明: 1.加密方式为MD5,32位小写 2.加密字段 MD5(AppKey+UID+EmployeeID+TA+ForCorp +Cost1+Cost2+Cost3+MD5(AppSecurity)) 示例:MD5("obk_test"+""+"test"+"TA001"+"0"+"costcenter1" +"costcenter2"+"costcenter3"+MD5("obk_test")) 加密后的值为:7aec59d0e0724318c77119aa6b051ed1 注意: 1. ForCorp字段如果不传,在生成MD5签名时需要传0 2. 字符串拼接必须按照上面的顺序 3. 参与加密的字段,必须在表单中传入单点登录接口 4. 加密字段包含中文,需使用UTF-8编码 5. 加密方法请参考:其他=>代码调用实例=>MD5 加密方法 |
|
TA | String | 关联行程号 | Y | 长度最长30 | |
ForCorp | Int | 因公出行,因私出行选择 | 0 | Y | 0:因公出行,1 :因私出行 |
Cost1 | String | 成本中心1 | Y | 客户公司提供,用于下游结算使用,单点登录只是将其写入Cookie | |
Cost2 | String | 成本中心2 | Y | 客户公司提供 | |
Cost3 | String | 成本中心3 | Y | 客户公司提供 | |
Cost4 | String | 成本中心4 | Y | 客户公司提供 | |
Cost5 | String | 成本中心5 | Y | 客户公司提供 | |
Cost6 | String | 成本中心6 | Y | 客户公司提供 | |
JourneyReason | String | 出行目的 | Y | 客户公司提供 | |
Project | String | 项目号 | Y | 客户公司提供 | |
Action | String | 员工登录后指向地址 | Y | ||
ActionParms | String | 登陆后执行地址附带参数,在指定Action时,可能需要传入 | Y | 当用户知道QueryString时可以精确填充如 p=xx&d=xxxx | |
Backurl | String | 定位URL | Y | 示例:http://vacations.ctrip.com/insurance/199, 如有用户使用ct.ctrip.com打头的地址,直接更改为ctripbiz.com打头的地址。需要跳转到携程商旅对应产品,地址详情见附录一。 | |
DefineFlag | String | 自定义字段 | Y | 用户需要特别处理预留的字段;成本中心4、5、6、出行目的、项目号和自定义字段1、2不可同时传输。 | |
DefineFlag2 | String | 自定义字段2 | Y | 用户需要特别处理预留的字段2;成本中心4、5、6、出行目的、项目号和自定义字段1、2不可同时传输。 | |
Name | String | 员工姓名 | Y | 员工姓名字段,针对TokenType = 1 有效。如果不传,Name默认为员工编号。长度最长支持80。 | |
FirstName | String | 英文名FirstName | Y | 员工英文名FirstName字段,针对TokenType = 1 有效。长度最长支持60。该字段不能够传中文字符,以及("<", ">", "!", "&",",","@","#","$","%","*","(",")","^" ,"\","/")这些特殊字符。自动开卡时:FirstName跟LastName都不为空的情况下,才会保存英文名。 | |
MiddleName | String | 英文名MiddleName | Y | 员工英文名MiddleName字段,针对TokenType = 1 有效。长度最长支持30。该字段不能够传中文字符,以及("<", ">", "!", "&",",","@","#","$","%","*","(",")","^" ,"\","/")这些特殊字符。 | |
LastName | String | 英文名LastName | Y | 员工英文名LastName字段,针对TokenType = 1 有效。长度最长支持30。该字段不能够传中文字符,以及("<", ">", "!", "&",",","@","#","$","%","*","(",")","^" ,"\","/")这些特殊字符。自动开卡时:FirstName跟LastName都不为空的情况下,才会保存英文名。 | |
SearchType | String | 搜索类型 | Y | 该字段传值后,Backurl将失效。传值规范: 1(国内机票)、 2(国际机票)、 3(国内酒店)、 4(海外酒店)、 5(火车票)、 103(国内酒店详情)、 104(海外酒店详情)。 具体每个产品的参数见3.2.1.1至3.2.1.5。 |
|
IsAutoPopUp | String | 是否自动弹出审批单列表 | Y | 有效值为T(自动弹框)或F(不自动弹框) 该字段仅在授权方式为提前审批且存在有效审批单场景生效 |
|
AuthorizerEmployeeID | String | 一次授权人员工编号 | Y | 支持的产品为:国内、国际机票和国内、海外酒店 |
|
Authorizer2EmployeeID | String | 二次授权人员工编号 | Y | 支持的产品为:国内、国际机票和国内、海外酒店 |
注意:如果POST信息含有中文,必须进行URL编码,字符集只支持UTF8
3.2.1.1 国内机票查询参数
字段 | 类型 | 描述 | 默认值 | 可为空 | 传值规则 |
CorpPayType | String | 预定类型 | N | C:因公 P:因私 |
|
FlightSearchType | String | 航程类型 | N | S:单程 D:往返M:联程 |
|
ClassType | String | 舱等类型 | 默认不限 | Y | Y:经济舱 CF:公务或头等舱 |
Airline | String | 航司二字码 | 默认不限 | Y | 航司二字码数据请联系实施经理字段长度限制为2 |
DDate1 | String | 第1程出发日期 | N | 日期格式为:YYYY-MM-DD ,如(2017-02-20) | |
DDate2 | String | 第2程出发日期 | Y | 航程类型为往返/联程时需必传日期格式为:YYYY-MM-DD ,如(2017-02-20) | |
DCity1 | String | 第1程出发城市三字码 | N | 城市三字码数据请联系实施经理字段长度限制为3如:SZX(深圳) | |
DCity2 | String | 第2程出发城市三字码 | 默认为ACity1值 | Y | 该字段不需传值,航程类型为往返/联程时,默认为第一程到达城市三字码 |
ACity1 | String | 第1程到达城市三字码 | N | 字段长度限制为3如:SZX(深圳) | |
ACity2 | String | 第2程到达城市三字码 | Y | 航程类型为往返/联程程时需必传字段长度限制为3如:SZX(深圳) | |
Flight | String | 航班号 | Y | 航班号,如CA1893 |
Demo 示例
在Form表单中添加如下字段:
1 2 3 4 5 6 7 8 9 10 |
|
3.2.1.2 国际机票查询参数
字段 | 类型 | 描述 | 默认值 | 可为空 | 传值规则 |
CorpPayType | String | 预定类型 | N | C:因公P:因私 | |
FlightSearchType | String | 航程类型 | N | S:单程D:往返M:联程 | |
ClassType | String | 舱等类型 | N | Y:经济舱S:超级经济舱C:公务舱F:头等舱 | |
Airline | String | 航司二字码 | 默认不限 | Y | 航司二字码数据请联系实施经理字段长度限制为2如:MU(东方航空) |
PassengerType | String | 乘客类型 | N | ADU:成人CHI:儿童 | |
PassengerQuantity | String | 乘机人数 | N | 最小传1 | |
IsDirect | String | 是否仅查看直飞 | 默认为否 | Y | T:仅查看直飞F:查看全部 |
DDate1 | String | 第1程出发日期 | N | 日期格式为:YYYY-MM-DD ,如(2017-02-20) | |
DDate2 | String | 第2程出发日期 | Y | 航程类型为往返/多程时需必传日期格式为:YYYY-MM-DD ,如(2017-02-20) | |
DDate3 | String | 第3程出发日期 | Y | 航程类型为多联程且航程数>=3 时需必传日期格式为:YYYY-MM-DD ,如(2017-02-20) | |
DDate4 | String | 第4程出发日期 | Y | 航程类型为多联程且航程数>=4 时需必传日期格式为:YYYY-MM-DD ,如(2017-02-20) | |
DDate5 | String | 第5程出发日期 | Y | 航程类型为多联程且航程数>=5 时需必传日期格式为:YYYY-MM-DD ,如(2017-02-20) | |
DDate6 | String | 第6程出发日期 | Y | 航程类型为多联程且航程数>=6 时需必传日期格式为:YYYY-MM-DD ,如(2017-02-20) | |
DCity1 | String | 第1程出发城市三字码 | N | 城市三字码数据请联系实施经理必传字段字段长度限制为3如:SZX(深圳) | |
DCity2 | String | 第2程出发城市三字码 | 默认为ACity1值 | Y | 航程类型为往返时该字段不需传值,默认为第一程到达城市三字码航程类型为多程是为必传字段长度限制为3如:SZX(深圳) |
DCity3 | String | 第3程出发城市三字码 | Y | 航程类型为多联程且航程数>=3 时需必传字段长度限制为3如:SZX(深圳) | |
DCity4 | String | 第4程出发城市三字码 | Y | 航程类型为多联程且航程数>=4 时需必传字段长度限制为3如:SZX(深圳) | |
DCity5 | String | 第5程出发城市三字码 | Y | 航程类型为多联程且航程数>=5 时需必传字段长度限制为3如:SZX(深圳) | |
DCity6 | String | 第6程出发城市三字码 | Y | 航程类型为多联程且航程数>=6 时需必传字段长度限制为3如:SZX(深圳) | |
ACity1 | String | 第1程到达城市三字码 | N | 必传字段字段长度限制为3如:SZX(深圳) | |
ACity2 | String | 第2程到达城市三字码 | Y | 航程类型为往返/多程时需必传字段长度限制为3 | |
ACity3 | String | 第3程到达城市三字码 | Y | 航程类型为多联程且航程数>=3 时需必传字段长度限制为3如:SZX(深圳) | |
ACity4 | String | 第4程到达城市三字码 | Y | 航程类型为多联程且航程数>=4 时需必传字段长度限制为3如:SZX(深圳) | |
ACity5 | String | 第5程到达城市三字码 | Y | 航程类型为多联程且航程数>=5 时需必传字段长度限制为3如:SZX(深圳) | |
ACity6 | String | 第6程到达城市三字码 | Y | 航程类型为多联程且航程数>=6 时需必传字段长度限制为3如:SZX(深圳) | |
FlightNumber | String | 航程数 | Y | 多程查询时必传,非多程不必传 | |
CurrentLang | String | 语言类型 | N | en:英文 zh_cn:简体中文 zh_hk:繁体中文 |
Demo 示例
在Form表单中添加如下字段:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
3.2.1.3 酒店查询参数
字段 | 类型 | 描述 | 默认值 | 可为空 | 传值规则 |
CorpPayType | String | 预定类型 | N | C:因公P:因私 | |
HotelType | String | 酒店类型 | N | M:会员酒店C:协议酒店 | |
CityID | String | 城市ID(数字格式) | N | 城市ID数据调用接口获取,接口文档路径:审批对接 -> 基数数据 -> 酒店城市数据 | |
CheckInDate | String | 入住日期 | N | 日期格式为:YYYY-MM-DD ,如(2017-02-20) | |
CheckOutDate | String | 离店日期 | N | 日期格式为:YYYY-MM-DD ,如(2017-02-20) | |
RoomNumber | String | 房间数 | Y | 搜索海外酒店时,该字段为必传 |
Demo 示例
在Form表单中添加如下字段:
1 2 3 4 5 6 |
|
3.2.1.4 酒店详情页面跳转参数
字段 | 类型 | 描述 | 默认值 | 可为空 | 传值规则 |
CorpPayType | String | 预定类型 | N | C:因公P:因私 | |
HotelType | String | 酒店类型 | N | M:会员酒店C:协议酒店 | |
CityID | String | 城市ID(数字格式) | N | 城市ID数据调用接口获取,接口文档路径:审批对接 -> 基数数据 -> 酒店城市数据 | |
HotelID | String | 酒店ID(数字格式) | N | 酒店ID数据请联系实施经理 | |
CheckInDate | String | 入住日期 | N | 日期格式为:YYYY-MM-DD ,如(2017-02-20) | |
CheckOutDate | String | 离店日期 | N | 日期格式为:YYYY-MM-DD ,如(2017-02-20) | |
RoomNumber | String | 房间数 | Y | 跳转海外酒店时,该字段为必传 | |
CurrentLang | String | 语言类型 | Y | en:英文 zh_cn:简体中文 zh_hk:繁体中文 |
Demo 示例
在Form表单中添加如下字段:
1 2 3 4 5 6 |
|
3.2.1.5 火车票查询参数
字段 | 类型 | 描述 | 默认值 | 可为空 | 传值规则 |
CorpPayType | String | 预定类型 | N | C:因公P:因私 | |
From | String | 出发城市/车站中文或英文名 | N | 城市数据调用接口获取,审批对接 -> 基数数据 -> 火车票车站数据 | |
To | String | 到达城市/车站中文或英文名 | N | 如:上海 | |
DDate | String | 出行日期 | N | 格式:yyyy-MM-dd | |
SearchG | String | 是否只搜索高铁动车 | Y | true/false | |
CurrentLang | String | 语言类型 | Y | en:英文 zh_cn:简体中文 zh_hk:繁体中文 |
Demo 示例
在Form表单中添加如下字段:
1 2 3 4 5 |
|
3.2.2.返回契约
返回 |
登录成功后,默认跳转到携程商旅登录后首页或到2.2.1中Backurl指定的页面或到指定产品搜索结果页面。 |
失败提示 |
参照2.3提示信息内容与编码 |
3.2.3.提示信息内容与编码
编码 | 提示信息 |
10301000 | 服务器未知错误,请联系管理员。 |
10301006 | 调用校验Token服务失败:{0}。 |
10301007 | 传入的公司ID和公司密码校验错误或IP受限,请联系携程! |
10301008 | 该用户已注销,请联系携程! |
10301009 | 验证是否为有效的用户失败:{0}。 |
10301014 | 登录请求发生异常:{0}。 |
10301015 | 获取登陆的Token失败:{0}。 |
10301016 | 身份校验失败。 |
10301017 | 签名校验失败,可能是数据已更改。 |
10301019 | 公司状态异常。 |
10301020 | 子账户无效 |
10301021 | 员工编号不能为空! |
10301023 | UID不存在,请联系携程! |
10301024 | UID或员工编号不属于该公司,请联系携程! |
10301025 | 很抱歉,您的账户未在携程注册,请联系贵司相关负责人,开通携程账户后方可登录。 Sorry that your account has not been registered in CTRIP Corporate online booking site. Please contact your company system manager in order to register your CTRIP account. |
10301028 | 参数存在错误。 |
10301032 | 从库中取到的公司ID为空,请联系携程! |
10301037 | token无效。 |
10301039 | token使用次数失效。 |
10301040 | 字段AppKey必须是一个字符串,其最小长度为1,最大长度为50。 |
10301041 | 字段Ticket必须是一个字符串,其最小长度为18,最大长度为32。 |
10301042 | 字段TA必须是最大长度为50的字符串。 |
10301043 | 字段Cost1必须是最大长度为100的字符串。 |
10301044 | 字段Cost2必须是最大长度为100的字符串。 |
10301045 | 字段Cost3必须是最大长度为100的字符串。 |
10301047 | 字段Action必须是最大长度为10的字符串。 |
10301048 | 字段Signature必须是最大长度为32的字符串。 |
10301049 | 字段DefineFlag必须是最大长度为100的字符串。 |
10301061 | 字段DefineFlag2必须是最大长度为100的字符串。 |
10301050 | 传入的UID和EmployeeID不能同时为空。 |
10301051 | 字段ForCorp必须是0或1的字符串。 |
10301052 | 字段AppSecurity必须是最大长度为50的字符串。 |
10301053 | Version可以不赋值,赋值只能为1.0或者2.0。 |
10301054 | TokenType可以不赋值,赋值只能为0或1或2。 |
10301055 | 接入账户不能为空 |
10301056 | 接入密码不能为空 |
10301057 | Ticket不能为空。 |
10301058 | GroupID字段格式必须是整型数据。 |
10301059 | UID未关联子账户。 |
10301062 | 卡号不存在 |
10301069 | FirstName,MiddleName,LastName不能包含中文 |
10301070 | FirstName,MiddleName,LastName不能包含特殊字符 |
10301071 | 当SearchType为{0}时,字段{1}为必传 |
10301072 | 当SearchType为{0}且{1}为{2}时,字段{3}为必传 |
10301073 | 当SearchType为{0}时,字段{1}的值无效,传入值为{2},有效值为{3} |
10301074 | 当SearchType为{0}时,字段{1}的格式无效,传入值为{2},正确格式为{3} |
10301075 | 当SearchType为{0}时,字段{1}的字节长度错误,传入值为{2},长度为{3},正确字节长度为{4} |
10301076 | 字段{0}传入值无效,传入值为{1},有效值为{2} |
10301077 | 当SearchType为{0}且{1}为{2}、{3}为{4}时,字段{5}为必传 |
10301078 | 当SearchType为{0}且{1}为{2}、{3}为{4}时,字段{5}格式无效,传入值为{6},正确格式为{7} |
10301079 | 当SearchType为{0}且{1}为{2}、{3}为{4}时,字段{5}的字节长度错误,传入值为{6},长度为{7},正确字节长度为{8} |
10301090 |
字段EmployeeID必须是最大长度为100的字符串。 |
10301091 |
字段IsAutoPopUp:{1}为非法值,有效值为T或F |
990 | 当前接口调用方式存在安全隐患,请改用https方式调用。 |
4.调用方法及代码示例
4.1.调用示例
protected void Button3_Click(object sender, EventArgs e)
{
string url = @"此部分内容请登录后查看";
string data = "{'AppKey':'***','AppSecurity':'***'}";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "POST";
request.ContentType = "application/json; charset=utf-8";
request.ContentLength = data.Length;
StreamWriter writer = new StreamWriter(request.GetRequestStream(), Encoding.ASCII);
writer.Write(data);
writer.Flush();
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
string encoding = response.ContentEncoding;
if (encoding == null || encoding.Length < 1)
{
encoding = "UTF-8";
}
StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
string retString = reader.ReadToEnd();
this.txtBox.Text = retString;
JavaScriptSerializer serialize = new JavaScriptSerializer();
JsonEntity entity = serialize.Deserialize<JsonEntity>(retString);
StringBuilder html = new StringBuilder();
html.Append("<html><body>");
html.Append("<form name='fLogin' id='fLogin' method='post' action='此部分内容请登录后查看'>");
html.AppendFormat("<input type='hidden' name='AppKey' value='***' />");
html.AppendFormat("<input type='hidden' name='Ticket' value='{0}' />", entity.Token);
html.AppendFormat("<input type='hidden' name='UID' value='wwwww' />");
html.AppendFormat("<input type='hidden' name='Signature' value='***' />");
html.Append("</form>");
html.Append("<script language='javascript'>window.document.fLogin.submit();</script>");
html.Append("</body></html>");
Response.Write(html.ToString());
}
public class JsonEntity
{
public string Token { get; set; }
public bool Success { get; set; }
}