微信授权登录实现分析
微信授权登录包含有几种场景:一是公众号;二是H5页面;三是其它APP;本文主要讲述公众号及H5页面的实现,关于其它APP的应用,请参考官方文档。
1. 公众号与H5
公众号应用其实也是H5页面,不过是H5页面在微信浏览器中打开。但这两种方式有着本质的区别。其最关键的不同在于,通过公众号打开H5页面可以直接弹出微信授权登录对话框,如下所示:
而使用其它浏览器只能打开一个二维码的页面:
在手机端要使用微信扫码,这个体验是非常之差劲的,只可惜微信目前并未对这种方式进行改进。对于H5页面如果想要兼容常规浏览器和公众号页面的,目前只有这种方式实现,聊胜于无!
另外一点需要注意的是:普通的h5页面应用和公众号应用,是两个应用,如在微信开放平台后台:
要实现公众号里面直接弹出微信授权登录对话框,需要使用公众账号中的应用,而普通浏览器,又需要使用网站应用。因此,我们必须在前端页面中识别出当前是不是微信浏览器打开的,然后再在后台接口中判断是使用哪个应用进行接口调用!不得不说腾讯这块真的是够烂,包括后续要写的支付那块,使用上与阿里的体验差距太大。
2. 应用创建
- 进公众平台申请公众号;
- 进微信开放平台申请网页应用;
注意如果只是在公众号中使用可以无需申请网页应用。如果想要兼容两个应用场景,那么两个都需要申请。
申请过程很简单,不再细述。
等待应用审核通过就可以继续下一步了。
注意应用审核通过后需要在应用详情中修改应用回调域:
应用回调域只能设置一个,比如我的应用是有两个地址的,一是m.ttcn.vip一是www.ttcn.vip,但在微信上只能设置一个,因此只好设置成www.ttcn.vip,然后通过后台的nginx进行跳转。
应用回调域就是在微信授权登录成功后返回的页面所在域名,如果授权登录时传的域名与此处配的域名不匹配,将会报redirect_uri参数错误异常。
3. 实现
微信授权登录等第三方授权登录基本采用的都是OAuth2的方式,具体实现原理可以查找相关文档,本文主要聚焦微信授权登录方面。与微信授权登录相关的流程如下所示:
3.1 组装获取授权码的请求参数
需要包含关键的几个参数如下:
参数 | 说明 |
---|---|
appid | 应用id,从微信开放平台中查看,注意公众号应用和网页应用的appid是不一样的 |
redirect_uri |
授权成功后的回调页面地址,微信将会将授权成功后的code作为URL参数来对回调页面进行调用 因此回调页面主要用于接收授权成功后的授权码,用于后续的接口调用 注意该参数需要进行URL编码 |
response_type | 授权码模式写死code,其它参考官方文档 |
scope |
应用授权作用域,拥有多个作用域用逗号(,)分隔,网页应用目前仅填写snsapi_login 公众号应用可以填写snsapi_userinfo |
state | 自定义参数 |
前端需要将这些参数拼装后跳转到微信授权登录页面去,需要注意的是,公众号与网页应用跳转的页面是不一样的,公众号需要跳转到:
https://open.weixin.qq.com/connect/oauth2/authorize
而网页应用需要跳转到:
https://open.weixin.qq.com/connect/qrconnect
前端VUE示例如下所示:
<template><div><el-button @click="wxLogin">微信登录</el-button> </div>
</template>
<script>export default {methods: {wxLogin() {// 获取浏览器标识,判断需要使用公众号还是网页应用var url = 'http://.../wx-login'; let UA = navigator.userAgent.toLocaleLowerCase();var loginUrl = "https://open.weixin.qq.com/connect/qrconnect?";if (UA.indexOf("micromessenger") !== -1) {// 使用公众号appIdloginUrl ="https://open.weixin.qq.com/connect/oauth2/authorize?";loginUrl +="appid=wx8******6c849c&" +"redirect_uri=" +encodeURIComponent(url) +"&response_type=code&" +"&scope=snsapi_userinfo&state=1#wechat_redirect";} else {// 使用网页应用appIdloginUrl +="appid=wxba******847&" +"redirect_uri=" +encodeURIComponent(url) +"&response_type=code&" +"&scope=snsapi_login#wechat_redirect";}window.location.replace(loginUrl);}}}
</script>
3.2 回调页面实现
微信授权登录成功后将会在指定的回调页面后拼上code参数返回,如假设回调页面是http://…/wx-login,那么返回的页面路径将会是:http://…/wx-login?code=…,在使用Vue实现的页面中,我们可以使用this.$route.query.code来获取到这个授权码,然后调用后台接口使用授权码获取token/openId并最终获取用户信息,wx-login.vue页面示例如下:
<template><div class="wx-login-page"><user-bind:initUserInfo="userInfo":state="state"v-if="needBind"></user-bind></div>
</template><script>
import userBind from "@/components/UserBind";export default {components: { userBind },props: [],data() {return {wxCode: "",userInfo: {},needBind: false,state: 0,};},mounted() {let UA = navigator.userAgent.toLocaleLowerCase();this.state = UA.indexOf("micromessenger") !== -1 ? 1 : 0; this.wxCode = this.$route.query.code;},methods: {getToken() {// 根据wxCode调用后台服务获取微信用户的openId,获取用户信息this.$get("/base/login/wx", {code: newValue,state: this.state,}).then((resp) => {if (resp.success) {// 不需要绑定,openId已经存在this.$setCookie("accessToken", resp.loginInfo.key);} else {// 如果是微信端绑定,需要绑定mpOpenIdlet openId =resp.userInfo.openId || resp.userInfo.openid;// 需要绑定this.userInfo = {nickname: resp.userInfo.nickname,image:resp.userInfo.headImage ||resp.userInfo.headimgurl,sex: resp.userInfo.sex,};if (0 === this.state) {this.userInfo.wxOpenId = openId;} else {this.userInfo.mpOpenId = openId;}this.needBind = true;}});}},
};
</script><style lang="scss">
.wx-login-page {}
</style>
以上页面主要就是调用后台/base/login/wx接口获取token/openId及用户信息;由于本项目应用场景需要,如果授权登录的用户是首次登录,还需要绑定手机号,因此后台会有一个判断,如果根据获取到的openId查询到的用户为空,则会调用微信获取用户信息的接口获取到用户信息并返回给前端,前端跳转到绑定页面进行用户绑定。而如果不是首次登录,则不需要获取用户信息及绑定这个步骤了。
另外,后台用户表设计了两个openId字段,一个存储网页应用的,一个存储公众号的;因为两个应用下的用户openId是不一样的。
3.3 后台获取openId及token实现
回调页面中调用的/base/login/wx接口实现如下:
/*** 微信登录** @param code 微信授权后的Code* @param state 登录方式,0:非微信浏览器;1:微信浏览器;* @return 登录信息*/
@GetMapping("/wx")
public ThirdLoginResultDTO wxLogin(@RequestParam("code") String code,@RequestParam(value = "state", defaultValue = "0") Integer state) {// 先根据code获取openIdWxAuthInfo authInfo = wxService.getAuthInfo(code, state);String openId = authInfo.getOpenId();ThirdLoginResultDTO result = new ThirdLoginResultDTO();// 根据openId查找用户Optional<UserDTO> userOptional = userService.findByWxOpenId(openId, state);if (userOptional.isPresent()) {// 如果已经存在,直接登录后返回UserDTO user = userOptional.get();BiValue<String, UserDTO> biValue = loginService.localLogin(user);result.setLoginInfo(biValue);result.setSuccess(true);return result;}// 不存在,返回给前端相关信息并进行绑定// 如果openId不存在,则需要将昵称等返回前端,在前端关联手机号进行绑定ThirdUserInfo thirdUserInfo = wxService.getUserInfo(authInfo, state);result.setSuccess(false);result.setUserInfo(thirdUserInfo);return result;
}
注意我这有一个本地登录的方法,因为我的后台服务使用的是OAuth2的授权模式,授权成功后需要自动根据用户信息获取到接口访问需要的accessToken,否则前端所有的接口访问仍旧是未授权的。
wxservice.getAuthInfo的实现如下:
/*** 通过授权码获取token等授权信息** @param code 授权码* @param state 微信登录来源,0:非微信浏览器,1:微信浏览器* @return 授权信息*/
public WxAuthInfo getAuthInfo(String code, Integer state) {String url = "https://api.weixin.qq.com/sns/oauth2/access_token";String result = RestClient.of(url).addUrlParam("appid", state.equals(0) ? APP_ID : MOBILE_APP_ID).addUrlParam("secret", state.equals(0) ? APP_SECRET : MOBILE_APP_SECRET).addUrlParam("code", code).addUrlParam("grant_type", "authorization_code").get(String.class);if (logger.isDebugEnabled()) {logger.debug("微信获取token结果: {}", result);}JSONObject jsonObject = JSONObject.parseObject(result);String accessToken = jsonObject.getString("access_token");String openid = jsonObject.getString("openid");WxAuthInfo authInfo = new WxAuthInfo();authInfo.setAccessToken(accessToken);authInfo.setOpenId(openid);return authInfo;
}
getUserInfo实现如下:
/*** 获取微信登录用户信息** @return 用户信息*/
public ThirdUserInfo getUserInfo(WxAuthInfo authInfo, Integer state) {String infoUrl = "https://api.weixin.qq.com/sns/userinfo";String str = RestClient.of(infoUrl).addUrlParam("access_token", authInfo.getAccessToken()).addUrlParam("openid", authInfo.getOpenId()).get(String.class);if (logger.isDebugEnabled()) {logger.debug("微信获取用户信息结果: {}", str);}if (str.contains("errorcode")) {throw BusinessException.create("微信接口调用失败,请尝试其它登录方式");}ThirdUserInfo userInfo = JSONObject.parseObject(str, ThirdUserInfo.class);return userInfo;
}
这样整个微信授权登录的过程就已经完成。
后续将继续总结QQ授权登录、微信支付及支付宝支付实现,感兴趣的可以关注本人。
微信授权登录实现分析相关推荐
- 微信授权登录mock(在没有真实微信账号的情况下测试大量微信账户授权登录的情况)...
场景介绍 对于构建在微信公众号的系统,帐号体系往往使用微信授权登录(如各类微信商城应用系统). 这样操作不仅可以实现静默注册,对用户几乎是无感的,同时也达到了区分用户,获取用户基本信息(头像,昵称等) ...
- 慕课网_《微信授权登录》学习总结
时间:2017年08月12日星期六 说明:本文部分内容均来自慕课网.@慕课网:http://www.imooc.com 教学源码:无 学习源码:https://github.com/zccodere/ ...
- html5+ mui框架 微信授权登录后跳回app无任何回调事件
2019独角兽企业重金招聘Python工程师标准>>> 微信授权登录可以调起微信,但是在微信上点击确认登陆后跳回app,但是之后无任何回掉事件. 问题原因: 1 因为我在集成Face ...
- thinkphp 微信授权登录 以及微信实现分享
<?php namespace app\wechat\controller; use think\Controller; use think\Request; /** * 微信授权登录类 * U ...
- ios微信登录不上服务器,iOS微信授权登录
首先需要确保你的App应用在微信开发平台上注册创建并获得对应的接口,对应登录.支付等功能还涉及付费,具体申请流程就不再这里说了.到开放平台->管理中心->移动应用->查看应用,确认你 ...
- code换取微信openid_微信授权登录开发的两种方式
本文主要针对微信公众号(公众平台的开发) 首先理解一个概念:OAuth: OAuth(开放授权)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表), ...
- 五行代码搞定微信授权登录
Authing 通过 SDK 为开发者提供了一种快速在微信网页中获取用户信息并完成登录的方法.如果用户在微信客户端中访问第三方网页.公众号可以通过微信网页授权机制,来获取用户基本信息,进而实现业务逻辑 ...
- Java版本微信授权登录(测试版)
这篇文章是对微信授权登录的一个测试版本,并不能直接在生产上使用,对于在生产上正式使用将会在下一篇中描述. 一,首先需要以下两个数据 appID和appsecret 如何获取这两个数据,请先登录微信公众 ...
- html5+ mui框架 微信授权登录无响应,不回跳APP
2019独角兽企业重金招聘Python工程师标准>>> 微信授权登录可以调起微信,但是在微信上点击确认登陆后无响应,不跳回到APP. 问题解决方法: 1. 参考文章做排除:http: ...
- 微信授权登录(微信订阅号使用测试账号)
1.微信授权登录: 微信公众号测试登录: 准备: 1.1 花生壳! 下载地址:http://hsk.oray.com/download/ 1.2 微信公众号:https://mp.weixin.qq. ...
最新文章
- 案例 | 蓝天智通:智办事助力“智慧校园”数智化管理,提升人效
- Hbuilder 常用快捷键汇总
- python安装教程win8-python 2.7在win8.1上安装的方法
- 分析vue-cli@2.9.3 搭建的webpack项目工程
- 【机器学习基础】机器学习中的特征工程总结!
- Qt Creator连接MCU
- 介绍ASP.NET控件ID
- 750px设计稿处理方式
- mega x_[MEGA DEAL]通过Hadoop Bundle掌握大数据(91%的折扣)
- 关于Xcode隐藏打印的logs的方法
- python3安装pymysql_python安装PyMySQL
- 【BZOJ3048】Cow lineup,贪心+队列维护(或二分答案)
- 我开着超市,不好好做自己的生意,每天却为社区团购平台打工
- Python的@property使用方法
- 想做程序员?不同方向入门路线全解
- 小米研发类Kindle电子阅读器
- VMware 注册码
- 那个程序员的 Linux 常用软件清单 | Linux 工具篇
- 为什么电脑屏幕会横过来_电脑屏幕横过来了怎么办
- ==和 equals 的区别
热门文章
- RTP payload format for VP9 video
- 同文输入法 android,同文输入法app下载-同文输入法手机版-同文输入法最新版_易玩网...
- 01 - 树莓派简介以及烧录系统
- mac 修改 hosts 文件之后,刷新 DNS 缓存
- 41个机器学习面试题
- MinGW编译windows可以调试的ffmpeg4.4
- 三轴加速度传感器的类型、原理、特点和应用
- ILSVRC竞赛详细介绍(ImageNet Large Scale Visual Recognition Challenge)
- 【JavaP6大纲】MySQL篇:为什么要分库分表(设计高并发系统的时候,数据库层面该如何设计)?用过哪些分库分表中间件?不同的分库分表中间件都有什么优点和缺点?你们具体是如何对数据库如何进行垂直拆分
- 产品经理/总监 面试题及答案