最近开发字节小程序 发现字节服务端demo实在是.....
所以我弄完手机号解密 就发上来 给大家玩耍学习
先决条件永远是环境
你的小程序要有手机号授权能力
开发环境 字节小程序 golang
这看有个要注意
**
1先登录
2在授权手机号
3才可以解密
**
小程序代码
js
Page({
data:{
},
getPhoneNumberHandler(e) {
console.log("------手机号-------");
console.log(e);
console.log("------手机号-------");
console.log(e.detail.errMsg);
console.log(e.detail.iv);
console.log(e.detail.encryptedData);
this.data.encryptedData = e.detail.encryptedData
this.data.iv = e.detail.iv
},
login_xxx(){
let that = this.data
tt.login({
force: true,
success(res) {
console.log("-------登录------");
console.log(res);
console.log("-------登录------");
console.log(`login 调用成功${res.code} ${res.anonymousCode}`);
that.code = res.code
that.anonymousCode = res.anonymousCode
},
fail(res) {
console.log(`login 调用失败`);
},
});
},
//自己写的服务端解密
sign_xxx(){
let that = this
tt.request({
url: 'http://xxxxxx.xxxx/xx/xx', // 目标服务器url
header: {
"content-type": "application/json",
"Authorization": "Bearer eyJhbGcIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2MjI3MTIyNzQsImlhdCI6MTYyMjYyNTg3NH0.j5LcJSLxpxDTd_iuDJltCE5HdE9sIu_W2l-6EyVsKag",
},
method: "POST",
data: {
"appid": "你小程序的appid",
"code": that.data.code,
"anonymous_code": that.data.anonymousCode,
"encryptedData": that.data.encryptedData,
"iv": that.data.iv
},
dataType:"json",
success: (res) => {
console.log(res)
}
});
}
});
html
<button bindtap="login_xxx">登录</button>
<button class="aaaaa" open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumberHandler">授权手机号</button>
<button class="aaaaa" bindtap="sign_xxx">解密</button>
下边是服务端代码 这边用的golang写的
byte code
package bytexcx
import (
"context"
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"github.com/tal-tech/go-zero/core/logx"
"poly/lib/request"
"time"
)
var (
ErrAppIDNotMatch = errors.New("app id not match")
ErrInvalidBlockSize = errors.New("invalid block size")
ErrInvalidPKCS7Data = errors.New("invalid PKCS7 data")
ErrInvalidPKCS7Padding = errors.New("invalid padding on input")
)
type AppSetting struct {
logx.Logger
Appkey, Secret string
}
const (
code2Session = "https://developer.toutiao.com/api/apps/jscode2session"
)
//用户数据
type CodeOpenID struct {
AnonymousOpenid string `json:"anonymous_openid"` //设备标识 IqSPkd0t2lvqAEsP
Error int `json:"error"` //0成功
Openid string `json:"openid"` //用户标识 张建武的 28452fbc-0678-4d35-81e6-82a1182106d7
SessionKey string `json:"session_key"` //用户解密铭感数据 如手机号
Unionid string `json:"unionid"` //用户在小程序平台的唯一标识符,请求时有 code 参数才会返回。如果开发者拥有多个小程序,可通过 unionid 来区分用户的唯一性。
}
//报错说明
type OpenIDErr struct {
Errcode int `json:"errcode"`
Errmsg string `json:"errmsg"`
Error int `json:"error"`
Message string `json:"message"`
}
type MobileInfo struct {
CountryCode string `json:"countryCode"`
PhoneNumber string `json:"phoneNumber"`
PurePhoneNumber string `json:"purePhoneNumber"`
Watermark struct {
Appid string `json:"appid"`
Timestamp int `json:"timestamp"`
} `json:"watermark"`
}
func NewAppSetting(appkey, secret string) *AppSetting {
return &AppSetting{logx.WithContext(context.TODO()), appkey, secret}
}
// 获取 OpenId
func (app *AppSetting) GetOpenId(code, anonymous_code string) (*CodeOpenID, error) {
url := fmt.Sprintf("%s?appid=%s&secret=%s&code=%s&anonymous_code=%s",
code2Session,
app.Appkey,
app.Secret,
code,
anonymous_code,
)
logx.Info("字节小程序 GetOpenId 请求: ", url)
http := &request.HttpRequest{
Url: url,
Month: "GET",
Data: nil,
Head: nil,
Timeout: 3 * time.Second, //3秒超时
}
data, err := http.Http()
logx.Info("字节小程序 GetOpenId 返回: ", url)
if err != nil {
return nil, err
}
open := &CodeOpenID{}
err = json.Unmarshal(data, open)
if err != nil {
return nil, err
}
if open.Error == 0 {
return open, nil
}
operr := &OpenIDErr{}
err = json.Unmarshal(data, operr)
if err != nil {
return nil, err
}
return nil, errors.New(operr.Message)
}
// 获取授权手机号
func (app *AppSetting) GetMobileInfo(data, key, iv string) (*MobileInfo, error) {
aesKey, err := base64.StdEncoding.DecodeString(key)
if err != nil {
return nil, err
}
cipherText, err := base64.StdEncoding.DecodeString(data)
if err != nil {
return nil, err
}
ivBytes, err := base64.StdEncoding.DecodeString(iv)
if err != nil {
return nil, err
}
block, err := aes.NewCipher(aesKey)
if err != nil {
return nil, err
}
mode := cipher.NewCBCDecrypter(block, ivBytes)
mode.CryptBlocks(cipherText, cipherText)
cipherText, err = pkcs7Unpad(cipherText, block.BlockSize())
if err != nil {
return nil, err
}
fmt.Println(string(cipherText))
info := new(MobileInfo)
err = json.Unmarshal(cipherText, info)
if err != nil {
return nil, err
}
return info, nil
}
// 获取用户信息
func (app *AppSetting) GetUserInfo() {
}
// pkcs7Unpad returns slice of the original data without padding
func pkcs7Unpad(data []byte, blockSize int) ([]byte, error) {
if blockSize <= 0 {
return nil, ErrInvalidBlockSize
}
if len(data)%blockSize != 0 || len(data) == 0 {
return nil, ErrInvalidPKCS7Data
}
c := data[len(data)-1]
n := int(c)
if n == 0 || n > len(data) {
return nil, ErrInvalidPKCS7Padding
}
for i := 0; i < n; i++ {
if data[len(data)-n+i] != c {
return nil, ErrInvalidPKCS7Padding
}
}
return data[:len(data)-n], nil
}
再贴一下http请求吧
package request
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"net/http"
"strings"
"time"
)
type HttpRequest struct {
Url string //请求地址
Month string //请求方法
Data []byte //请求内容
Head map[string]string //请求头
Timeout time.Duration //超时时间
}
// 发送GET请求
// url: 请求地址
// response: 请求返回的内容
func Get(url string) string {
// 超时时间:5秒
client := &http.Client{Timeout: 5 * time.Second}
resp, err := client.Get(url)
if err != nil {
panic(err)
}
defer resp.Body.Close()
var buffer []byte
result := bytes.NewBuffer(nil)
for {
n, err := resp.Body.Read(buffer[0:])
result.Write(buffer[0:n])
if err != nil && err == io.EOF {
break
} else if err != nil {
panic(err)
}
}
return result.String()
}
// 发送POST请求
// url: 请求地址
// data: POST请求提交的数据
// contentType: 请求体格式,如:application/json
// content: 请求放回的内容
func (hp *HttpRequest) Http() (result []byte, err error) {
// 超时时间
client := &http.Client{Timeout: hp.Timeout}
req, err := http.NewRequest(hp.Month, hp.Url, strings.NewReader(string(hp.Data)))
if err != nil {
fmt.Println(err.Error())
return
}
for key, header := range hp.Head {
req.Header.Set(key, header)
}
res, err := client.Do(req)
if err != nil {
fmt.Println(err)
return
}
defer res.Body.Close()
result, err = ioutil.ReadAll(res.Body)
if err != nil {
return
}
return
}