微信小程序后端接口:登陆,检验,数据解密
微信小程序登陆接口
-
根据 appid secret 和 code 获取session_key 和 openid
微信小程序校验接口
-
获取前端数据rawData和signature
-
rawData和session_key通过sha1加密后与signature进行合法性校验
微信小程序数据解密
-
获取前端数据encryptedData和iv
-
session_key为aeskey
-
通过base64解码后,进行aes CBC模式PKCS7解密
微信小程序登陆流程
-
先调用wx.login()获取code,把code传到服务端,服务端根据code调用微信接口换取openid,可以把openid跟你的账户关联起来。如果数据库中没有这个openid那就算注册,返回小程序需要注册。如果有,那就返回小程序注册过,返回一个token之类的来作为登录状态。
-
小程序收到服务端返回的token缓存起来,下次进入小程序的时候就不用再调用wx.login(),而是直接调用业务接口就可以了。
-
服务器A拿到session_key后,生成一个随机数我们叫3rd_session,以3rdSessionId为key,以session_key + openid为value缓存到redis或memcached中;因为微信团队不建议直接将session_key在网络上传输,由开发者自行生成唯一键与session_key关联。其作用是: (1)将3rdSessionId返回给客户端,维护小程序登录态。
(2)通过3rdSessionId找到用户session_key和openid。
-
客户端拿到3rdSessionId后缓存到storage。
-
通过wx.getUserIinfo可以获取到用户敏感数据encryptedData 。
-
客户端将encryptedData、3rdSessionId和偏移量一起发送到服务器A。
-
服务器A根据3rdSessionId从缓存中获取session_key。
-
在服务器A使用AES解密encryptedData,从而实现用户敏感数据解密。
登陆后可获取的用户信息
-
openid 用户的唯一标识
-
nickname 用户昵称
-
sex 用户的性别,值为1时是男性,值为2时是女性,值为0时是未知
-
province 用户个人资料填写的省份
-
city 普通用户个人资料填写的城市
-
country 国家,如中国为CN
-
headimgurl 用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空。若用户更换头像,原有头像URL将失效。
-
privilege 用户特权信息,json 数组,如微信沃卡用户为(chinaunicom)
-
unionid 只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段。
代码
部分代码如下:
package auth
type Auth interface {
SetOpenID2SessionKey(openID, sessionKey string) error
GetSessionKeyByOpenID(openID string) (string, error)
GetAllUser() (map[string]string, error)
}
var DefaultAuth = NewMemoryAuth()
package auth
type MemoryAuth struct {
openID2sessionKey map[string]string
}
func NewMemoryAuth() Auth {
return &MemoryAuth{
openID2sessionKey: map[string]string{},
}
}
func (ma *MemoryAuth) GetAllUser() (map[string]string, error) {
return ma.openID2sessionKey, nil
}
func (ma *MemoryAuth) SetOpenID2SessionKey(openID, sessionKey string) error {
ma.openID2sessionKey[openID] = sessionKey
return nil
}
func (ma *MemoryAuth) GetSessionKeyByOpenID(openID string) (string, error) {
return ma.openID2sessionKey[openID], nil
}
func Login(ctx *httpserver.Context, code string, conf *Config) (string, error) {
rsp := &Code2SessionKeyRsp{}
err := httputil.NewClient().
SetPostParam("code", code).
SetPostParam("client_id", conf.AppKey).
SetPostParam("sk", conf.SecrectKey).
SetHeader("Content-Type", "application/x-www-form-urlencoded").
SetPath(" ").
PostMethod().
Do().
RspJson(rsp, func(data interface{}) error {
if data.(*Code2SessionKeyRsp).ErrorNo != 0 {
return httputil.BadContent
}
return nil
}).
Error()
if err != nil {
ctx.Warning(err)
return "", err
}
e := authdata.DefaultAuth.SetOpenID2SessionKey(rsp.OpenID, rsp.SessionKey)
if e != nil {
ctx.Warning(e)
return "", e
}
return rsp.OpenID, nil
}
type Code2SessionKeyRsp struct {
OpenID string `json:"openid"`
SessionKey string `json:"session_key"`
Error string `json:"error"`
ErrorNo int64 `json:"errno"`
ErrorDescription string `json:"error_description"`
}