字节小程序 授权手机号 go解密

最近开发字节小程序 发现字节服务端demo实在是.....

所以我弄完手机号解密 就发上来 给大家玩耍学习


先决条件永远是环境

你的小程序要有手机号授权能力

开发环境 **字节小程序 golang**


这看有个要注意

1先登录

2在授权手机号

3才可以解密



小程序代码

js

html
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

html
<view class="intro">个人中心</view>

<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
}

伍先生
  • 职业: 程序员,产品
  • 码龄: 5.2
  • 技能: PHP Go 前端
  • 微信: JwCode
  • 公众号/小程序: 渐悟分享