概述

OAuth即开放授权协议,其提供了一个安全、可靠的框架供第三方应用在一定授权和限制下访问HTTP服务。智慧山师使用OAuth版本为OAuth 1.0a及xAuth,若需要使用我们的OAuth接口,请联系我们获取Consumer Key以及Consumer Secret,其中由于安全性的问题,目前向全校师生开放的仅为OAuth 1.0a接口。

OAuth按使用情况分为服务提供者(Service Provider)和服务使用者(Consumer),其中智慧山师开放平台即为服务提供者,使用智慧山师公共平台的应用均为服务使用者。

使用流程

OAuth 1.0a的授权流程非常简单,总体分为三个步骤:

  1. 服务使用者(应用)向智慧山师请求未授权的Request Token
  2. 服务使用者向智慧山师请求用户身份授权,智慧山师引导用户访问智慧山师授权页面(仅第一次需要),经用户同意后Request Token变为已授权
  3. 服务使用者使用已授权的Request Token向智慧山师换取Access Token

当第三方应用获取到Access Token后就可以使用其获取指定权限的用户信息了。

全过程流程如下:

OAuth授权流程

授权流程

若要使用OAuth接口,首先您需要申请获取Consumer Key和Consumer Secret,其中Consumer Secret是您应用的密钥,在请求过程中需要使用其进行加密,所以请妥善保管。

当用户第一次使用您的应用时(或Access Token过期时),您需要首先获取用户的Access Token,在获取到用户的Access Token后,您才可以根据您的权限获取用户的信息。

获取Request Token

获取Request Token是OAuth 1.0a协议用户认证的第一步,首先您需要准备好以下的参数:

参数名参数说明
oauth_callback第二步用户授权时的回调地址
oauth_consumer_keyConsumer Key
oauth_nonce单次值,最长32位字符串
oauth_signature签名
oauth_signature_method签名方法,固定为“HMAC-SHA1”
oauth_timestamp时间戳
oauth_version协议版本,固定为“1.0”

对于桌面或手机App这类没有服务器的应用来说,也可以使用智慧山师默认的Callback地址http://i.sdnu.edu.cn/oauth/index.html,使用内置浏览器访问授权页后监视页面的跳转即可。

为了方便大家阅读,约定说明文档中所有参数均统一设置为以下内容:


参数名示例内容
oauth_consumer_keytest_consumer_key
oauth_consumer_secrettest_consumer_secret
oauth_nonce00000000000000000000000000000000
oauth_timestamp9999999999
oauth_callbackhttp://fakeurl.com/callback?from=isdnu
x_auth_username2013001001
x_auth_password123456

使用上述参数生成BaseString,需要注意的是callback中的url虽然也包含参数from=isdnu,但该参数属于callback地址的一部分,并非OAuth的认证参数,不需要单独提取出来。生成的BaseString如下:

GET&http%3A%2F%2Fi.sdnu.edu.cn%2Foauth%2Frequest_token&oauth_callback%3Dhttp%253A%252F%252Ffakeurl.com%252Fcallback%253Ffrom%253Disdnu%26oauth_consumer_key%3Dtest_consumer_key%26oauth_nonce%3D00000000000000000000000000000000%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D9999999999%26oauth_version%3D1.0

此时由于还未获取到任何Token,所以此时的密钥只包含oauth_consumer_secret及“&”连字符,即如下所示:

test_consumer_secret&

所以此时生成的签名为:

pXIKYBEoaeAREuOgRAJQpdqAP+A=

接下来就可以向http://i.sdnu.edu.cn/oauth/request_token请求,请求时附带的Authorization Header如下:

OAuth oauth_callback="http%3A%2F%2Ffakeurl.com%2Fcallback%3Ffrom%3Disdnu",oauth_consumer_key="test_consumer_key",oauth_nonce="00000000000000000000000000000000",oauth_signature="pXIKYBEoaeAREuOgRAJQpdqAP%2BA%3D",oauth_signature_method="HMAC-SHA1",oauth_timestamp="9999999999",oauth_version="1.0"

不论请求是否成功,都会返回文本字符串,返回的ContentType为“text/plain”。其中请求成功后,服务器会返回如下未授权的Request Token ID、Request Token对应的密钥以及设定Callback的确认信息,其中这三个字段分别使用“&”连接,例如返回的内容为:

oauth_token=11111111111111111111111111111111&oauth_token_secret=2222222222222222222222222222222222222222&oauth_callback_confirmed=true

此时请将Request Token ID及对应的密钥记录下来,在第二步中将使用。

如果请求失败则会返回如下内容:

error_code=10006&error_type=auth_error&error_description=signature+is+invalid

其中返回的内容均使用“&”符号进行分割,分割后可以分别获取错误代码、错误类型以及错误描述,其中错误描述使用UrlEncode进行处理。

请求用户授权

这一步使用刚才获取到的Request Token请求服务器以引导到授权页面并获得用户的授权。通常,Web应用程序可以跳转到授权页面,当用户授权成功后再跳转到第一步设置的Callback地址然后完成接下来的操作;而桌面或手机App则需要使用应用内置浏览器引导用户访问智慧山师授权页面,然后监视浏览器页面的跳转。

智慧山师的用户授权地址为:http://i.sdnu.edu.cn/oauth/authorize,访问时需要将上一步获取的Request Token ID附带在oauth_token参数中。如果用户是第一次授权,则会出现一个页面,用户可以在该页面上使用智慧山师账户登录并同意或拒绝授权;如果用户之前已经授权过,则会直接跳转到上一步设置的Callback地址。默认该页面会读取当前已经登录的用户状态,如果需要让用户强制登录,在调用接口时需要附加额外的参数forcelogin=true,默认不填写此参数相当于forcelogin=false。

例如,通过上一步获取到的Request Token,这一步应该访问的地址为:

http://i.sdnu.edu.cn/oauth/authorize?oauth_token=11111111111111111111111111111111

如果用户成功授权,则会带着参数跳转到第一步设置的Callback地址:

http://fakeurl.com/callback?from=isdnu#oauth_token=11111111111111111111111111111111&oauth_verifier=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

其中oauth_token与之前请求的Request Token完全相同,此时请将oauth_verfier验证码记录下来,在第三步中将使用。

换取Access Token

用户完成授权后,可以使用之前的Request Token换取正式的Access Token,首先需要准备以下的参数:

参数名参数说明
oauth_consumer_keyConsumer Key
oauth_nonce单次值,最长32位字符串
oauth_signature签名
oauth_signature_method签名方法,固定为“HMAC-SHA1”
oauth_timestamp时间戳
oauth_token第一步获得的Request Token ID
oauth_verifier第二步获得的验证码
oauth_version协议版本,固定为“1.0”

此时生成的BaseString如下:

GET&http%3A%2F%2Fi.sdnu.edu.cn%2Foauth%2Faccess_token&oauth_consumer_key%3Dtest_consumer_key%26oauth_nonce%3D00000000000000000000000000000000%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D9999999999%26oauth_token%3D11111111111111111111111111111111%26oauth_verifier%3Daaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa%26oauth_version%3D1.0

由于此时已经有了Request Token,所以此时加密的密钥为:

test_consumer_secret&2222222222222222222222222222222222222222

用该加密密钥对上述的BaseString进行加密,获取到的签名如下:

fUlh49IUIjFKxpR+lSODB3HpYAo=

然后就可以向http://i.sdnu.edu.cn/oauth/access_token请求,请求时附带的Authorization Header如下:

OAuth oauth_consumer_key="test_consumer_key",oauth_nonce="00000000000000000000000000000000",oauth_signature="fUlh49IUIjFKxpR%2BlSODB3HpYAo%3D",oauth_signature_method="HMAC-SHA1",oauth_timestamp="9999999999",oauth_token="11111111111111111111111111111111",oauth_verifier="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",oauth_version="1.0"

如果请求成功,则服务器就会返回Access Token ID、Access Token对应的密钥以及用户学工号、用户类型以及Access Token的超时时间:

oauth_token=33333333333333333333333333333333&oauth_token_secret=4444444444444444444444444444444444444444&user_id=2013001001&user_type=1&expires_in=604800

其中用户类型分别为0-本科生,1-研究生,2-教职工。返回内容类型与request_token接口一样为文本字符串,失败时返回类型与request_token相同。

信息获取

在获取了Access Token以后,就可以使用信息接口根据权限获取所需要的信息了。其中公共权限接口可以不传oauth_token参数,即不进行OAuth认证。

若要获取信息,首先需要准备以下的参数:

参数名参数说明
oauth_consumer_keyConsumer Key
oauth_nonce单次值,最长32位字符串
oauth_signature签名
oauth_signature_method签名方法,固定为“HMAC-SHA1”
oauth_timestamp时间戳
oauth_tokenAccess Token ID
oauth_version协议版本,固定为“1.0”

除了OAuth固定的参数外,对于部分服务还需要添加其特定的参数。但这些参数不属于OAuth特定的参数,不需要放在HTTP请求头中,可以放在QueryString或Form中,不过不论放在QueryString还是Form中都需要在生成BaseString时包含在参数集合中。

例如使用GET方法获取用户信息,则请求的地址为http://i.sdnu.edu.cn/oauth/rest/people/get,所以BaseString为:

GET&http%3A%2F%2Fi.sdnu.edu.cn%2Foauth%2Frest%2Fpeople%2Fget&oauth_consumer_key%3Dtest_consumer_key%26oauth_nonce%3D00000000000000000000000000000000%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D9999999999%26oauth_token%3D00000000000000000000000000000000%26oauth_version%3D1.0

此时已经有了Access Code,所以当前密钥应该如下:

test_consumer_secret&4444444444444444444444444444444444444444

使用上述密钥加密后的签名为:

uaaIvtZusfri9s1nixxSBcWb/O0=

所以最终请求时的Authorization Header为:

OAuth oauth_consumer_key="test_consumer_key",oauth_nonce="00000000000000000000000000000000",oauth_signature="uaaIvtZusfri9s1nixxSBcWb%2FO0%3D",oauth_signature_method="HMAC-SHA1",oauth_timestamp="9999999999",oauth_token="00000000000000000000000000000000",oauth_version="1.0"

不论成功还是失败,均返回Json文本,返回的ContentType为“application/json”。对于成功后返回的信息为实体直接序列化后的Json文本,例如:

{
    "identityNumber":"2013001001",
    "name":"张三",
    "idCardNumber":"",
    "sex":"男",
    "nation":"汉族",
    "organizationID":"010310",
    "organizationName":"信息科学与工程学院"
}

而若请求失败,则返回错误Json信息,返回的内容与授权接口的内容相同,但表现形式不同,例如:

{
    "errorCode":10006,
    "errorType":"auth_error",
    "errorDescription":"signature is invalid"
}

创建签名

所有使用OAuth接口的请求都需要生成签名,签名生成的流程为:生成签名字符基串(Signature Base String)及使用密钥加密生成密钥两步。

生成BaseString

Base String是把HTTP请求方法名、请求完整URL地址以及请求参数用“&”字符连起来后做RFC3986 Encode编码(类似于各个平台自带的UrlEncode,但是对空格替换为“%20”,而不是“+”)。其中请求参数需要把所有的请求参数(包括POST方法体中的参数),经过排序(按参数名进行文本排序,如果参数名有重复则再按参数值进行重复项目排序),使用%3D替代=号,并且使用%26作为每个参数之间的分隔符,拼接成一个字符串。

这个算法可以简单表示为:

httpMethod + "&" +
  url_encode( base_uri ) + "&" +
  sorted_query_params.each { | k, v |
      url_encode ( k ) + "%3D" + url_encode ( v )
  }.join("%26")

例如,使用GET方式请求获取Request Token:http://i.sdnu.edu.cn/oauth/request_token

请求参数为:

oauth_callback=http://fakeurl.com/callback?from=isdnu
oauth_consumer_key=test_consumer_key
oauth_nonce=00000000000000000000000000000000
oauth_signature_method=HMAC-SHA1
oauth_timestamp=9999999999
oauth_version=1.0

则最终的BaseString为:

GET&http%3A%2F%2Fi.sdnu.edu.cn%2Foauth%2Frequest_token&oauth_callback%3Dhttp%3A%2F%2Ffakeurl.com%2Fcallback%3Ffrom%3Disdnu%26oauth_consumer_key%3Dtest_consumer_key%26oauth_nonce%3D00000000000000000000000000000000%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D9999999999%26oauth_version%3D1.0

加密生成签名

智慧山师的签名统一使用HMAC-SHA1算法进行加密,加密的密钥如下:

oauth_consumer_secret + "&" + oauth_token_secret

需要注意的是,其中的oauth_token_secret始终与当前使用的令牌密钥相同,如果当前未使用密钥则留空,但“&”符号应需要保留。即当使用Request Token换取Access Token的过程时使用的oauth_token_secret为Request Token的密钥;而当获取用户个人信息则使用Access Token的密钥。

对于请求Request Token的过程,由于此时并未获取任何Token,所以此时的密钥为如下:

test_consumer_secret&

使用该密钥加密后则可以获得加密后最终的签名

VDfVbXtO+moqLuqL7MzqRs4Hnc4=

创建HTTP请求头

为了保障安全性,智慧山师开放平台要求所有的OAuth参数都必须在Http Header中进行传输,即将所有参数按键值对的方式放在HTTP的Authorization请求头中(建议按顺序排列),其算法如下:

"OAuth " + 
  sorted_header_params.each { | k, v |
      url_encode ( k ) + "=\"" + url_encode ( v ) + "\""
  }.join(",")

例如使用上一节的参数和创建的签名则可以获取如下的请求头:

OAuth oauth_callback="http%3A%2F%2Ffakeurl.com%2Fcallback%3Ffrom%3Disdnu",oauth_consumer_key="test_consumer_key",oauth_nonce="00000000000000000000000000000000",oauth_signature="VDfVbXtO%2BmoqLuqL7MzqRs4Hnc4%3D",oauth_signature_method="HMAC-SHA1",oauth_timestamp="9999999999",oauth_version="1.0"

其他参数说明

时间戳 Timestamp

时间戳使用Unix时间,即当前时间转换为UTC时间后,减去1970年1月1日0时0分0秒后的所有秒数。当客户端时间与服务器时间相差超过8分钟时无效,认证失败。

例如,当前时间为2014/1/29 16:56:58(UTC+8),其UTC时间为2014/1/29 8:56:58,减去Unix起始时间为16099天8时56分58秒,共计1390985818秒,故时间戳为1390985818。

单次值 Nonce

唯一值为每次请求时不重复的字符串,防止重放攻击,最长为32个字符。如使用GUID生成唯一值时,可以以十六进制小写字符串表示。

例如,在.NET中使用Guid.NewGuid()生成的Guid为FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF。所以最终提交的Nonce为ffffffffffffffffffffffffffffffff。

错误代码

错误类型 错误代码 错误描述 适用范围
auth_error 10001 protocol version not supported 令牌请求接口 request_token
令牌授权接口 access_token
服务提供接口 rest
10002 timestamp invalid
10003 nonce invalid
10004 nonce repeated
10005 signature method not supported
10006 signature invalid
10007 callback url empty
10008 http method invalid
10009 duplicated parameter
10101 consumer key invalid
10102 consumer not allow user auth
10103 consumer no permission
10104 consumer not enabled
10201 consumer no xauth permission 令牌授权接口 access_token
token_error 11001 request token owner invalid 令牌授权接口 access_token
11002 request token empty
11003 request token invalid
11004 request token not authorized
11005 request token verifier empty
11006 request token verifier invalid
11011 user not authorized
11101 access token owner invalid 服务提供接口 rest
11102 access token empty
11103 access token invalid
11104 permission not authorized
xauth_error 12001 auth mode not supported 令牌授权接口 access_token
12101 username empty
12102 password empty
12103 username or password wrong
12104 user has not set an email address
rest_error 20001 rest method invalid 服务提供接口 rest
29999 各服务的特定错误(中文)