ByteDance MicroApp Login
2020-05-23 本文已影响0人
JunChow520
对比微信小程序登录流程
微信小程序登录流程字节跳动小程序登录
登录流程客户端
客户端使用tt.login()
方法获取登录临时凭证code
值,code
值有效期3分钟。客户端获取code
之后需通过调用服务端接口来向小程序后端发起登录凭证校验以获取用户信息。
tt.login({force:boolean, success:function, fail:function, complete:function});
接口参数
参数 | 类型 | 默认值 | 必填 | 描述 |
---|---|---|---|---|
force | boolean | true | N | 是否强制调起登录框 |
success | function | - | N | 登录成功回调函数 |
fail | function | - | N | 登录失败回调函数 |
complete | function | - | N | 登录完成回调函数,不管成功或失败都会执行。 |
调起登录框
force:boolean = true
-
force
参数用于控制用户未登录时是否强制调起登录框,force
参数是可选项默认值为true
。 - 如果用户未在端登录,比如没有在头条App中登录时,此时则会调起端的登录窗口。
- 如果用户点击登录框中的取消按钮则会调用
fail
回调函数。
登录失败
fail:function(res){
console.log("login fail", res.errMsg);
tt.showToast({title:"登录失败", duration:2000});
}
fail
登录失败回调函数,返回一个具有errMsg
登录失败信息参数的对象。
success:function(res){
const code = res.code;
const anonymousCode = res.anonymousCode;
const isLogin = res.isLogin;
}
登录成功
success
登录成功回调函数携带一个object
对象类型的参数返回,object
对象包含属性分别是code
、anonymousCode
、isLogin
、errMsg
。
例如:
{errMsg: "login:ok", anonymousCode: "7f50f5eda4923235", code: "231be4a26fec3d23", isLogin: true}
属性 | 类型 | 描述 |
---|---|---|
errMsg | string | 错误信息 |
isLogin | boolean | 是否已登录 |
code | string | 登录临时凭证 |
anonymousCode | string | 匿名登录凭证 |
isLogin
布尔值,用于判断在当前App中用户是否已经处于登录状态。
临时登录凭证
-
code
即临时登录凭证,有效期3分钟。只有端登录成功的success
中会出现code
值,否则只会出现anonyousCode
值。 -
code
值得作用时向服务端请求后接口以获取用户信息,用户信息中openid
是用户身份的唯一标识。
匿名登录凭证
-
anonyousCode
匿名登录凭证code值用于标识当前设备,无论登录与否都会返回,有效期3分钟。 -
anonymousCode
的作用是用来向服务端请求接口以获取anonmous_openid
即设备的唯一标识,比如同一台手机的anonmous_openid
值是唯一且相同的。
临时登录凭证code
和匿名登录凭证anonymousCode
在向服务端请求时都只能使用1次
例如:客户端进入首页立即执行登录操作
$ vim pages/index/index.js
Page({
onLoad: function () {
const self = this;
console.log('Welcome to Mini Code');
tt.login({force:true, success:function(res){
console.log("login success", res);
const isLogin = res.isLogin;
if(isLogin){
const code = res.code;
const anonymousCode = res.anonymousCode;
let data = {code, anonymousCode};
let url = "http://127.0.0.1:7001/api/bytedance/code2session";
self.httpGet(url, data, function(res){
}, function(res){
});
}
},fail:function(res){
const anonymousCode = res.anonymousCode;
console.log("login fail", res.errMsg);
tt.showToast({title:"登录失败", duration:2000});
}});
},
httpGet:function(url, data, success, fail){
const method = "GET";
const dataType = "json";
const header = {"content-type":"application/json"};
const responseType = "text";
tt.request({method, dataType, header, responseType, data, url, success:function(res){
console.log("request success", res);
success(res);
}, fail(res){
console.log("request fail", res);
fail(res);
}});
}
});
获取用户信息
//获取用户基本信息
tt.getUserInfo({
fail(res){
console.log("用户信息获取失败");
},
success(res){
console.log(res);
}
});
tt.getUserInfo
获取已登录用户的基本信息或特殊信息,需用户授权后方可调用,依赖于登录接口,调用前确定已调用tt.login
。
tt.getUserInfo({success, fail, complete, withCredentials});
参数 | 类型 | 默认 | 必须 | 描述 |
---|---|---|---|---|
success | function | - | N | 成功回调 |
fail | function | - | N | 失败回调 |
complete | function | - | N | 结束回调 |
withCredentials | boolean | false | N | 是否需返回敏感数据 |
成功返回
{
errMsg: "getUserInfo:ok",
rawData: "{"nickName":"junchow","avatarUrl":"http://sf1-ttcdn-tos.pstatp.com/img/mosaic-legacy/3795/3033762272~120x256.image","gender":0,"city":"","province":"","country":"中国","language":""}",
userInfo: {…}
}
属性 | 类型 | 说明 |
---|---|---|
userInfo | object | 用户信息 |
rawData | string | 原始数据,userInfo的JSON字符串形式。 |
userInfo用户信息所包含的字段
{
avatarUrl: "http://sf1-ttcdn-tos.pstatp.com/img/mosaic-legacy/3795/3033762272~120x256.image"
city: ""
country: "中国"
gender: 0
language: ""
nickName: "junchow"
province: ""
}
参数 | 类型 | 描述 |
---|---|---|
avatarUrl | string | 用户头像 |
nickName | string | 用户昵称 |
gender | number | 用户性别 0未知 1男性 2女性 |
city | string | 用户城市 |
province | string | 用户省份 |
country | string | 用户国家 |
language | string | 用户语言 |
解码敏感数据
//获取用户基本信息
tt.getUserInfo({
withCredentials:true,
fail(res){
console.log("用户信息获取失败");
},
success(res){
console.log(res);
}
});
若输入中传递了withCredentials:true
参数则返回对象的参数会增加如下扩展属性
{
errMsg: "getUserInfo:ok",
encryptedData: "ZM0mKGYyL+NdCTpl5OC6zzQuLMXjp1oQyHAcqEpAiXHc4SRs5g…7rtekDrIB5nWrHLYGnrSmBfDoK6epKglBGRd1uVHjZWW6+Zj8",
iv: "lS+u05jr8obZ5YOtuvet7A==",
signature: "d82e33764cefd6cc90b1f58c9ac180055f38e6df",
rawData: "{"nickName":"junchow","avatarUrl":"http://sf1-ttcd…y":"","province":"","country":"中国","language":""}",
userInfo: {nickName: "junchow", avatarUrl: "http://sf1-ttcdn-tos.pstatp.com/img/mosaic-legacy/3795/3033762272~120x256.image", gender: 0, city: "", province: "", …}
}
属性 | 类型 | 说明 |
---|---|---|
signature | string | 签名,用于校验用户信息是否被篡改。 |
encryptedData | string | 加密数据,包括敏感信息在内的已加密用户数据。 |
iv | string | 加密算法参数 |
敏感数据可提供后端进行验证后保存到数据库
signature
签名算法:校验数据合法性
const crypto = require("crypto");
const sha1 = val=>crypto.createHash("sha1").update(val).digest("hex");
const sigature = sha1(`${rawData}${session_key}`)
encryptedData
敏感数据解析
- 对称解密算法为
AES-128-CBC
,数据采用PKCS#7
填充。 - 对称解密的目标密文为
encryptedData
- 对称解密密钥
aeskey = base64decode(session_key)
,其中aeskey
长度为16Byte。 - 对称解密算法初始向量
base64decode(iv)
const crypto = require("crypto");
const decipher = crypto.createDecipheriv(
"aes-128-cbc",
Buffer.from(sessionKey, "base64"),
Buffer.from(iv, "base64")
);
let ret = decipher.update(encryptedData, "base64");
ret += decipher.final();
let data = JSON.parse(ret);
解密后的encryptdData
可获得属性
属性 | 类型 | 描述 |
---|---|---|
openId | string | 用户 openId |
watermark | object | 敏感数据水印 |
avatarUrl | string | 用户头像 |
nickName | string | 用户昵称 |
gender | number | 用户性别 0未知 1男性 2女性 |
city | string | 用户城市 |
province | string | 用户省份 |
country | string | 用户国家 |
language | string | 用户语言 |
watermark
敏感数据水印属性包括
属性 | 类型 | 描述 |
---|---|---|
appid | string | 数据源小程序 id |
timestamp | number | 时间戳,可以用于检查数据的时效性。 |
错误说明
{"error": "error:0606506D:digital envelope routines:EVP_DecryptFinal_ex:wrong final block length"}
服务端
服务端登录接口为code2session
,即客户端请求login
接口获取到登录凭证code
和anonmousCode
后,
在服务端发送code2session
请求以获取会话密钥session_key
和openid
。
会话密钥
-
session_key
随着客户端tt,login
接口调用而刷新 -
session_key
可通过tt.checkSession
方法验证当前session
是否有效以避免频繁登录 -
session_key
是对用户数据进行加密签名的密钥,为了数据安全,服务端不应将其下发到小程序,也不应对外提供。
接口地址
GET https://developer.toutiao.com/api/apps/jscode2session
接口参数
参数 | 描述 |
---|---|
appid | 小程序AppID,开发者后台获取。 |
secret | 小程序AppSecret,开发者后台获取。 |
code | 前端tt.login 接口返回的临时登录凭证 |
anonymous_code | 前端使用tt.login 接口返回的匿名登录凭证 |
错误返回
data:{
errcode: 40018,
errmsg: 'bad code',
error: 3,
message: 'bad code'
},
字段 | 类型 | 描述 |
---|---|---|
errcode | number | 错误编号 |
errmsg | string | 错误信息 |
错误编码
errcode | errmsg |
---|---|
-1 | 系统错误 |
0 | 请求成功 |
40015 | appid错误 |
40017 | secret错误 |
40018 | code错误 |
4019 | anonmous_code错误 |
其它 | 参数为空 |
成功返回
data: {
anonymous_openid: '',
error: 0,
openid: 'I25ZjrxP5R0xjrlj',
session_key: 'WpUS27etxV7AQ9VBaToDbA=='
}
参数 | 描述 |
---|---|
error | 是否出错,0否1是。 |
openid | 用户在当前小程序的ID,仅在请求时存在code 参数时才会返回。 |
session_key | 会话密钥,仅在请求时存在code 参数时才返回。 |
anonmous_openid | 匿名用户在当前小程序中的ID,尽在请求时存在anonymous_code 时才返回。 |