Sign in With Twitter之服务端验证

前言

本文是关于如何集成Twitter第三方登录。与Google等不同的是,Twitter的第三方登录采用的是OAuth 1.0开放授权标准,所以在向授权服务器发送请求的时候需要注意了。

OAuth 1.0

关于OAuth的详细介绍,可以参考维基百科 ,下面介绍在Twitter的第三方登录中,如何发起一个授权请求。

根据Twitter 官方文档 显示,需要在http请求的Header中包含足够识别请求者身份信息的内容,这些内容放在Authorization字段中。

Authorization中需要包含的参数有:

参数名
oauth_consumer_key Twitter client_id
oauth_nonce 每次请求的唯一凭证,Twitter将根据此值来判断是否是已经被提交了多次,需要Base64编码,长度为32字节,不能有特殊字符
oauth_signature 签名,除了oauth_signature字段本身的其他字段的签名
oauth_signature_method 签名方法,固定值: HMAC-SHA1
oauth_timestamp 请求时间戳,精确到秒
oauth_token access_token
oauth_version 固定值: 1.0

构建Authorization的值,假设代表最终值的变量名为DST字符串(初始值为空)

  1. 追加字符串"OAuth "(包括一个空格)到DST
  2. 百分号编码 参数名,并将其追加到DST
  3. 将字符=追加到DST
  4. 追加"DST
  5. 百分号编码 参数值,并将其追加到DST
  6. 追加"DST
  7. 如果还有剩余到参数键值对,则追加,(包含一个空格)到DST

最后得到的DST应该是下面这种格式:

OAuth oauth_consumer_key="xvz1evFS4wEEPTGEFPHBog", oauth_nonce="kYjzVBB8Y0ZFabxSWbWovY3uYSQ2pTgmZeNu2VS4cg", oauth_signature="tnnArxj06cWHq44gCs1OSKk%2FjLY%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1318622958", oauth_token="370773112-GmHxMAgYyLbNEtIKZeRNFsMKPR9EyMZeS9weJAEb", oauth_version="1.0"

关于签名

上面提到Authorization中需要包含签名,Twitter采用的签名类型是: HMAC-SHA1, 与微信支付类似,除了签名字段本身外,其他字段全部需要参与到签名中去,不同的是Twitter的签名还需要包含HTTP请求方法,以及请求的URL。

所以,最终Twitter待签名的字符串由三部分组成: HTTP请求方法(POST/GET等,大写),请求的API URL(如:https://api.twitter.com/1.1/statuses/update.json,URL需要URL编码),以及由参数组成的键值对。

参数签名步骤如下:

  1. 百分号编码 每个参与到签名的键值对,key与value都需要编码
  2. 将编码后的键值对根据key的字母顺序排序
  3. 将编码后的key追加到目标签名字符串中
  4. 每个key后面追加一个=字符
  5. 将每个key对应的编码后的value追加到=后面
  6. 如果还有剩余的key/value,则使用字符&连接每个键值对

最后得到的参数键值对字符串的格式如下:

include_entities=true&oauth_consumer_key=xvz1evFS4wEEPTGEFPHBog&oauth_nonce=kYjzVBB8Y0ZFabxSWbWovY3uYSQ2pTgmZeNu2VS4cg&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1318622958&oauth_token=370773112-GmHxMAgYyLbNEtIKZeRNFsMKPR9EyMZeS9weJAEb&oauth_version=1.0&status=Hello%20Ladies%20%2B%20Gentlemen%2C%20a%20signed%20OAuth%20request%21

所以最后的待签名字符串格式应该为:

POST&https%3A%2F%2Fapi.twitter.com%2F1.1%2Fstatuses%2Fupdate.json&include_entities%3Dtrue%26oauth_consumer_key%3Dxvz1evFS4wEEPTGEFPHBog%26oauth_nonce%3DkYjzVBB8Y0ZFabxSWbWovY3uYSQ2pTgmZeNu2VS4cg%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1318622958%26oauth_token%3D370773112-GmHxMAgYyLbNEtIKZeRNFsMKPR9EyMZeS9weJAEb%26oauth_version%3D1.0%26status%3DHello%2520Ladies%2520%252B%2520Gentlemen%252C%2520a%2520signed%2520OAuth%2520request%2521

接下来是获取签名用的key,key由两部分组成: consumer secretOAuth token secret,其中consumer secret在Twitter后台获取,OAuth token secret的获取由几种方式,将在后面介绍。

假设consumer secret的值为: kAcSOqF21Fu85e7zjz7ZN2U4ZRhfV3WpwPAoE3Z7kBw, OAuth token secret的值为: LswwdoUaIvS8ltyTt5jkRh4J50vUPVVHtR2YPi5kE

分别将二者进行百分号编码 ,然后使用&将二者连接在一起,即组成签名密钥: kAcSOqF21Fu85e7zjz7ZN2U4ZRhfV3WpwPAoE3Z7kBw&LswwdoUaIvS8ltyTt5jkRh4J50vUPVVHtR2YPi5kE

这里需要注意的一点是, 在某些尚未获取到OAuth token secret的API中,签名密钥的格式为: kAcSOqF21Fu85e7zjz7ZN2U4ZRhfV3WpwPAoE3Z7kBw&,即没有OAuth token secret

最后就是用签名密钥进行签名:

key := "kAcSOqF21Fu85e7zjz7ZN2U4ZRhfV3WpwPAoE3Z7kBw&LswwdoUaIvS8ltyTt5jkRh4J50vUPVVHtR2YPi5kE"
toBeSignStr := "POST&https%3A%2F%2Fapi.twitter.com%2F1.1%2Fstatuses%2Fupdate.json&include_entities%3Dtrue%26oauth_consumer_key%3Dxvz1evFS4wEEPTGEFPHBog%26oauth_nonce%3DkYjzVBB8Y0ZFabxSWbWovY3uYSQ2pTgmZeNu2VS4cg%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1318622958%26oauth_token%3D370773112-GmHxMAgYyLbNEtIKZeRNFsMKPR9EyMZeS9weJAEb%26oauth_version%3D1.0%26status%3DHello%2520Ladies%2520%252B%2520Gentlemen%252C%2520a%2520signed%2520OAuth%2520request%2521"

m := hmac.New(sha1.New, []byte(key))
m.Write([]byte(toBeSignStr))
m.Sum(nil)
sign := base64.StdEncoding.EncodeToString(m.Sum(nil))

获取OAuth token secret

Twitter的每个API请求都需要进行签名,在开始之前你可以在Twitter APP详情页面 对下面这些值进行配置:

oauth_consumer_key, oauth_consumer_secret: 当发起API请求时,可以将这两个值视为Twitter开发者应用的用户名和密码

oauth_token, oauth_token_secret: 在OAuth 1.0中,这两个值是用于发起API请求的特定用户的身份凭证,它们标识了API请求是由哪个Twitter账号发起的。如果你愿意使用相同的oauth_token, oauth_token_secret,则可以在Twitter APP详情页面 进行配置,那么每个用户请求API时都将使用同一对oauth_tokenoauth_token_secret。当然你可以让不同的用户使用不同的oauth_tokenoauth_token_secret。如下:

Request URL: POST https://api.twitter.com/oauth/request_token

Request POST Body: N/A

Authorization Header: OAuth oauth_nonce="K7ny27JTpKVsTgdyLdDfmQQWVLERj2zAK5BslRsqyw", oauth_callback="http%3A%2F%2Fmyapp.com%3A3005%2Ftwitter%2Fprocess_callback", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1300228849", oauth_consumer_key="OqEqJeafRSF11jBMStrZz", oauth_signature="Pc%2BMLdv028fxCErFyi8KXFM%2BddU%3D", oauth_version="1.0"

Response: oauth_token=Z6eEdO8MOmk394WozF5oKyuAv855l4Mlqo7hhlSLik&oauth_token_secret=Kd75W4OQfb2oJTV0vzGzeXftVAwgMnEK9MumzYcM&oauth_callback_confirmed=true

Sign in With Twitter接入步骤

  1. 获取oauth_token, oauth_token_secret(客户端)

由客户端向Twitter服务器发起获取token的Request请求, 根据OAuth 1.0a, Http Header中的Authorization需要添加的字段有:

参数名
oauth_callback 用户点击登录按钮后,客户端需要用户重定向到的URI,URI需要URL编码,该值需要在Twitter 后台 注册
oauth_consumer_key Twitter client_id
oauth_nonce 每次请求的唯一凭证,Twitter将根据此值来判断是否是已经被提交了多次,需要Base64编码,长度为32字节,不能有特殊字符
oauth_signature 签名,除了oauth_signature字段本身的其他字段的签名
oauth_signature_method 签名方法,固定值: HMAC-SHA1
oauth_timestamp 请求时间戳,精确到秒
oauth_version 固定值: 1.0
  1. 用户重定向(客户端)

利用步骤1获取到的oauth_token调用API: https://api.twitter.com/oauth/authenticate: https://api.twitter.com/oauth/authenticate?oauth_token={oauth_token} ,用户将会重定向到指定页面并且做出相应选择:

|登录并授权|如果用户登录twitter.com并且已经批准了调用应用程序,则将立即对它们进行身份验证,并使用有效的OAuth请求令牌返回回调URL。重定向到twitter.com对用户来说不明显|
|登录但不授权|如果用户登录到twitter.com但尚未批准调用应用程序,将显示与调用应用程序共享访问权限的请求。接受授权请求后,用户将被重定向到带有有效OAuth请求令牌的回调URL|
|不登录|如果用户未登录twitter.com将提示他们在屏幕上输入相同的访问权限。登录后,用户将使用有效的OAuth请求令牌返回回叫URL|

一旦成功但授权,你的callback_url将会收到包含oauth_tokenoauth_verifier参数,你的应用应该校验该oauth_token是否和步骤1中获取到的oauth_token匹配

  1. 获取用于身份验证的oauth_token, oauth_token_secret(客户端)

为了转换token为可用的access_token口令,你需要调用POST-oauth/access_tokenAPI,包含oauth_verifieroauth_token参数,并且需要签名。一个成功的调用,API将会返回oauth_tokenoauth_token_secret,客户端将这两个值传给服务端,服务端用以验证用户信息。

同时,获取access_token的API为: POST-https://api.twitter.com/oauth/access_token, 比如: POST https://api.twitter.com/oauth/access_token?oauth_token=qLBVyoAAAAAAx72QAAATZxQWU6P&oauth_verifier=ghLM8lYmAxDbaqL912RZSRjCCEXKDIzx, access_token的获取最好放在服务端。

  1. 身份验证(服务端)

服务端调用API: GET-account/verify_credentials来验证此次登录的用户信息是否有效。

参考资料

Twitter 官方文档
Twitter APP详情页面
Twitter 后台
百分号编码
OAuth 1.0a

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,163评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,301评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,089评论 0 352
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,093评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,110评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,079评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,005评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,840评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,278评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,497评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,667评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,394评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,980评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,628评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,649评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,548评论 2 352

推荐阅读更多精彩内容