曲线救国 — 微信个人开发者使用微信账号登录APP

之前在《应用商店上架记》一文中写过,关于三方登录中的微信账号登录不针对个人开发者开放的问题。就在这几天搜索了一下个人开发者微信登录的问题,有人提出了可以使用小程序的登录来实现微信登录。思考了一下,按照这个逻辑应该是可行的。因为小程序本身已经具备微信登录的相关能力,并且之前小程序也上架了。

现在需要解决的问题就剩下这么几个:
1.在微信小程序实现微信登录相关功能
2.从 app 直接调用小程序登录页面,获取 openid或者登录凭证
3.将小程序获取的 opendi 或者登录凭证调期 app,将相关的凭证回传 app 之后,app 使用相关的凭证进行登录。
有了思路之后,后面就一步一步来实现吧:

一、小程序登录

1.获取小程序 appid,登录微信公众平台,官网链接:https://mp.weixin.qq.com/ 。点击开发管理页面查看小程序 appid  
2.在 hbuilder 中修改 manifest.json 配置,微信小程序配置页面,填入微信小程序 appid  
3.获取微信用户信息,可以使用uni.getUserProfile请求用户授权获取用户信息。接口文档地址:https://uniapp.dcloud.net.cn/api/plugins/login.html#getuserprofile 
接口返回数据:
参数 类型 说明
userInfo OBJECT 用户信息对象
rawData String 不包括敏感信息的原始数据字符串,用于计算签名。
signature String 使用 sha1( rawData + sessionkey ) 得到字符串,用于校验用户信息。
encryptedData String 包括敏感数据在内的完整用户信息的加密数据,详细见加密数据解密算法。
iv String 加密算法的初始向量,详细见加密数据解密算法。
cloudID String 敏感数据对应的云 ID,开通云开发的小程序才会返回,可通过云调用直接获取开放数据,详细见云调用直接获取开放数据
errMsg String 描述信息
不过调用该接口返回的数据,并没有太多的实际价值,多数数据都是空的。
4.在能够获取基础数据之后,后续调用登录登录接口才能拿到凭证信息。
使用uni.login方法,provider参数输入’weixin’,成功的返回值中如果errMsg=“login:ok” 代表成功,
微信小程序端会返回一个code字符串
5.拿到 code 之后通过服务端代码换取 openid  文档地址: https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/user-login/code2Session.html
 
前端完整代码如下:
vue部分:
<!-- #ifdef APP-PLUS||MP -->
            <view class="fh-wechat-login-main">
                <slot>
                    <view class="fh-wechat-login-button" @click="dowechatLogin">
                        <view class="fh-wechat-icon"></view>
                        使用微信账号登录
                    </view>

                </slot>
            </view>
            <!--  #endif -->
 
js 部分:
dowechatLogin() {
                // 展示加载框
                uni.showLoading({
                    title: '加载中',
                });
                let url = this.$baseUrl +
                    'api/third-login/wechat-login/';
                uni.getUserProfile({
                    desc: '登录后可同步数据',
                    success: async (obj) => {
                        console.log('obj', obj);
                        // 调用 action ,请求登录接口
                        // await this.login(obj);
                        uni.login({
                            provider: 'weixin',
                            success: (res) => {
                                console.log('res-login', res);
                                this.code = res.code;
                                console.log('code', res.code);
                                if (res.errMsg == 'login:ok') {
                                    uni.request({
                                        url: url,
                                        data: {
                                            code: this.code
                                        },
                                        method: "POST",
                                        header: {},
                                        success: (res) => {
                                            // console.log(res.data);
                                            
                                        },
                                        fail: (e) => {
                                            console.log('failed:', e);
                                            uni.showToast({
                                                title: '登录失败,请稍候再试',
                                                icon: 'none'
                                            });
                                            this.isLoginProcess = false;
                                        }
                                    });
                                    console.log('res', res);
                                }
                            },
                        });
                    },
                    fail: err => {
                        console.log(err)
                        uni.showToast({
                            title: '授权已取消',
                            icon: 'error',
                            mask: true,
                        });
                    },
                    complete: () => {
                        // 隐藏loading
                        uni.hideLoading();
                    },
                });
            },

服务端部分:

def wechat_login(self, request):
        try:
            # user = request.user
            # user = User.objects.get(pk=1)
            try:
                code = request.data['code']
                resp = requests.get(
                    'https://api.weixin.qq.com/sns/jscode2session?appid=appid&secret=secrct&js_code=' + code + '&grant_type=authorization_code ')
                resp_json = json.loads(resp.text)
                if 'errcode' in resp_json:
                    return ErrorResponse(_('code 已经被使用'))
                # return DetailResponse(resp_json)
                # print(resp_json)
                user_info = resp_json
                # print(user_info)
                open_id = user_info['openid']
                # auth_realname = user_info['auth_realname']
                # 创建用户账号逻辑省略
                msg = {'token': token.key,
                       'user': {}
                       }
                return DetailResponse(msg)

            except Exception as e:
                print("Exception=", e)
                return ErrorResponse(_('数据错误'))

        except:
            return ErrorResponse(_('错误的数据格式'))
 
至此,小程序登录部分就算完成了。后端拿到授权获取的 code 之后通过接口换出 openid,基于 openid 进行账号创建。并且将账号信息返回小程序,实现登录功能。
 

二、app 打开小程序并且调起登录授权页面

1. 配置 uniapp 的微信分享功能
此处填写的 appid 跟上面的小程序的 appid 是一样的。
配置完成之后,在调试的时候需要重新进行自定义基座打包,并且运行的时候选择自定义基座。否则会提示打包不包含 share 模块。
 
2. app 打开小程序,相关代码:
appToMp() {
                let that = this
                let url = '/pages/page/wechatLogin' //跳转小程序的路径
                plus.share.getServices(function(res) {
                    var sweixin = null;
                    for (var i = 0; i < res.length; i++) {
                        var t = res[i];
                        if (t.id == 'weixin') {
                            sweixin = t;
                        }
                    }
                    if (sweixin) {
                        that.wxPay = true
                        sweixin.launchMiniProgram({
                            id: 'gh_8**********', //这里写你的小程序原始id(以gh开头)
                            type: 0, //微信小程序版本类型可取值: 0-正式版; 1-测试版; 2-体验版。 默认值为0。
                            path: url,
                            success(res) {
                                // return true
                                console.log('success=', res);
                            },
                            fail(res) {
                                uni.showToast({
                                    title: '跳转小程序失败',
                                    icon: 'none',
                                    duration: 3000
                                })
                                console.log('跳转小程序失败', res)
                                return false;
                            },
                        })
                    }
                }, function(err) {
                    console.log(JSON.stringify(err));
                })
            },
需要注意的是launchMiniProgram方法中的 id 为小程序原始 id,gh 开头的 id,如下图,小程序账号信息页面查看:
3. 登录微信开放平台,地址:https://open.weixin.qq.com/ 创建 app 并且提交审核。
在 ios 应用部分配置Universal Links,如下图:
4. 创建apple-app-site-association文件,并且上传到Universal Links根目录下,要求必须为 https。
文件内容如下:
{  
    "applinks": {  
        "apps": [],  
        "details": [  
            {  
                "appID": "appTeamID.bundleid",  
                "paths": ["/uni-universallinks/*"]  
            }  
        ]  
    }  
}
appID为 teamid+ bundleid 的组合。具体可以登录苹果开发者后台查看
 
例如 teamid 为 abcdef,则 appID 为,abcdef.my.dayi.app
5. 同时需要启用上图中的Associated Domains,在 uniapp 项目中配置Associated Domains。打包时需要下载最新的 mobileprovison 文件进行打包测试。
6. 在微信开放平台绑定小程序,点击绑定小程序按钮输入小程序的账号密码进行绑定。
 
上述流程如果配置出现问题可能会出现下面的错误提示
此时就只能根据微信的文档进行排查了:https://docs.msdk.qq.com/v5/zh-CN/FAQS/402d19e50fff44c827a4f3b608bd5812/11796f3fcca548e16afca803e76e5265.html
 
到这里第二步就算完成了,剩下的第三步就简单了。
 

三、获取授权凭证跳会 app 进行自动登录 

1. 小程序内创建授权登录页面,在这个页面需要能够获取 code 之后,并且回传到 app 内。跳转 app 需要使用独立的button 进行操作:
vue 代码:
<view v-if="isSuccess===0" class="fh-wechat-login-main" >
                <slot>
                    <view  class="fh-wechat-login-button" @click="LoginForWechat">
                        <view class="fh-wechat-icon"></view>
                        使用微信账号登录
                    </view>
                </slot>
            </view>
            <view v-if="isSuccess===1">
                <button class="fh-wechat-login-main" open-type="launchApp" :app-parameter="params" @error="openError"
                    style="font-size: 14px;">授权成功,点击返回APP登录</button>
            </view>
 
isSuccess用于控制获取到 code 之后显示返回 app 按钮。
js 代码:
uni.getUserProfile({
                    desc: '登录后可同步数据',
                    success: async (obj) => {
                        console.log('obj', obj);
                        // 调用 action ,请求登录接口
                        // await this.login(obj);
                        uni.login({
                            provider: 'weixin',
                            success: (res) => {
                                console.log('res-login', res);
                                this.code = res.code;
                                console.log('code', res.code);
                                if (res.errMsg == 'login:ok') {
                                    this.params = 'code=' + this.code;
                                    console.log('res', res);
                                    this.isSuccess = 1;
                                }
                            },
                        });
                    },
                    fail: err => {
                        console.log(err)
                        uni.showToast({
                            title: '授权已取消',
                            icon: 'error',
                            mask: true,
                        });
                    },
                    complete: () => {
                        // 隐藏loading
                        uni.hideLoading();
                    },
                });
通过params进行参数传递
 
2. app 获取小程序回传的code 凭证进行登录操作
js 代码:
onShow() {		
            // #ifdef APP-PLUS
            setTimeout(() => {
                console.log('wechat login call back')
                let code = plus.runtime.arguments
                if (code && code.toString().indexOf('code=')>=0) {
                    plus.runtime.arguments = ''
                    // ...
                    console.log('code=', code);

                    code = code.replace('code=', '');
                    if (code.length > 4) {
                        //使用 code 进行登录操作
                        this.httpLoginwechatWithCode(code);
                    }
                }

            }, 10)
            // #endif
        },
至此,整个微信账号登录的流程就算完成了,实际效果:
 
参考链接:
https://codeantenna.com/a/j7qBaSRtQd
https://blog.51cto.com/gblfy/5670283
https://docs.msdk.qq.com/v5/zh-CN/FAQS/402d19e50fff44c827a4f3b608bd5812/11796f3fcca548e16afca803e76e5265.html
☆版权☆

* 网站名称:obaby@mars
* 网址:https://h4ck.org.cn/
* 个性:https://oba.by/
* 本文标题: 《曲线救国 — 微信个人开发者使用微信账号登录APP》
* 本文链接:https://h4ck.org.cn/2024/02/15213
* 短链接:https://oba.by/?p=15213
* 转载文章请标明文章来源,原文标题以及原文链接。请遵从 《署名-非商业性使用-相同方式共享 2.5 中国大陆 (CC BY-NC-SA 2.5 CN) 》许可协议。


You may also like

28 comments

  1.  Level 5
    Google Chrome 119 Google Chrome 119 Mac OS X 10.15 Mac OS X 10.15 cn北京市 联通

    你这个方法现在有人用吗,一旦用的人多了,微信就会….

    1. 公主 Queen 
      Google Chrome 118 Google Chrome 118 Mac OS X 10.15 Mac OS X 10.15 cn山东省青岛市 联通

      这个登录是小程序的正常功能,并没有用一些不被允许的方法。所有的功能都是正常调用的,不存在使用私有 api 之类的。

      1.  Level 5
        Google Chrome 119 Google Chrome 119 Mac OS X 10.15 Mac OS X 10.15 cn北京市 联通

        只要没碰到滥用的就没事,好多开发者会滥用权限,然后查到授权到个人开发者app了,就有可能收回权限,应该不至于,一个登陆还不算什么隐私功能,只是有这种可能。

        1. 公主 Queen 
          Google Chrome 118 Google Chrome 118 Mac OS X 10.15 Mac OS X 10.15 cn山东省青岛市 联通

          现在个人开发者本来就没有微信登录的权限,所以还回收啥呢?难道小程序也不让用微信账号登录了?
          这个登录连账号基础信息都拿不到,昵称,性别,用户名都是空的。意思是微信啥信息都没给,最后用 code 换了个 openid 用来登录,已经够寒酸了。
          授权获取手机号是收费的,我也不需要手机号。所以,已经这么磕碜的功能了,也没什么好回收的了吧?😂
          唯一有用的就是那个 openid,如果这个也不给了,那就哪天再把微信登录给关了呗。

          1. Level 1
            Microsoft Edge 120 Microsoft Edge 120 Windows 10 Windows 10 cn湖南省邵阳市 联通

            授权获取手机号收费了?几年前还不收费来着,好久没碰过微信小程序了
            看了演示,感觉还挺丝滑的

        2. 公主 Queen 
          Google Chrome 118 Google Chrome 118 Mac OS X 10.15 Mac OS X 10.15 cn山东省青岛市 联通

          1.未认证无法使用微信登录
          未认证
          2.认证需要企业资质
          企业

    1. 公主 Queen 
      Google Chrome 120 Google Chrome 120 Windows 10 Windows 10 cn山东省临沂市 联通

      每年维护也是个问题。这个等后期看看情况,不过也想过这个办法

  2.  Level 4
    IBrowse r IBrowse r Android 10 Android 10 cn河南省漯河市 联通

    不明觉厉!手机图标和红点消息密集症恐惧者 laugh1最后一个图片添加闺蜜的提示文字有错别字。

    1. 公主 Queen 
      Google Chrome 118 Google Chrome 118 Mac OS X 10.15 Mac OS X 10.15 cn山东省青岛市 联通

      也不是这个意思,🍳来说所有的第三方登录本质上是做账号关联,账号系统还是自己管理。不管是微信还是 qq 都是通过授权登录换取 openid,在自己的账号系统内通过 openid 进行账号关联。
      做这个的主要用处是简化用户注册登录流程。

    1. 公主 Queen 
      Google Chrome 118 Google Chrome 118 Mac OS X 10.15 Mac OS X 10.15 cn山东省青岛市 联通

      还有啊,你的博客发不了评论了一直失败呢。想问你漫画风用的哪个模型来着。

    1. 公主 Queen 
      Google Chrome 120 Google Chrome 120 Windows 10 Windows 10 cn山东省临沂市 联通

      曲线救国,也算是个解决方案吧。毕竟国内用微信的用户群体还是非常大的,有了微信登录会方便很多。

  3. Level 1
    Microsoft Edge 120 Microsoft Edge 120 Windows 10 Windows 10 cn湖南省邵阳市 联通

    实际测试无法登陆,不知道是不是微信版本低的缘故

    1. 公主 Queen 
      Google Chrome 120 Google Chrome 120 Android 10 Android 10 cn山东省临沂市 联通

      什么表现?授权成功跳转回app没登陆吗?重启下app试试

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注