当前位置:网站首页>Day113.尚医通:微信登录二维码、登录回调接口
Day113.尚医通:微信登录二维码、登录回调接口
2022-07-30 09:11:00 【焰火青年·】
目录
一、微信扫描登录准备
官网:微信开放平台
1. 注册、资质
(1)登录注册
(2)激活、完善开发者资料
(3)开发者资质认证
(4)创建网站应用
(5)获取开发必要参数

2. 明确三方对接方式
1.SDK:按照要求导入相关依赖 (对接相关信息封装到依赖内)
2. API:访问固定地址,传递固定数目参数,参考API文档。会使用httpclient工具
3. 登录流程
文档:微信开放平台
时序图|泳道图

二、微信扫描登录二维码
1、后端接口实现
1、查看文档
方式一:拼写url进行重定向页面跳转
方拾二:通过js实现二维码获取

2、准备工作
1. 添加配置信息
#没有自动配置类 需要手动读取
# 微信开放平台 appid
wx.open.app_id=你的appid
# 微信开放平台 appsecret
wx.open.app_secret=你的appsecret
# 微信开放平台 重定向url
wx.open.redirect_url=http://你的服务器名称/api/ucenter/wx/callback2. utils 包下创建常量类
@Component
//@PropertySource("classpath:application.properties") 变量名需要与配置文件相匹配
public class ConstantPropertiesUtil implements InitializingBean {
@Value("${wx.open.app_id}")
private String appId;
@Value("${wx.open.app_secret}")
private String appSecret;
@Value("${wx.open.redirect_url}")
private String redirectUrl;
public static String WX_OPEN_APP_ID;
public static String WX_OPEN_APP_SECRET;
public static String WX_OPEN_REDIRECT_URL;
@Override
public void afterPropertiesSet() throws Exception {
WX_OPEN_APP_ID = appId;
WX_OPEN_APP_SECRET = appSecret;
WX_OPEN_REDIRECT_URL = redirectUrl;
}
}3. 实现接口
1. 接口分析
*参数:无
*返回值:map (获取二维码参数)

2. 实现 WeixinApiController
@Api(tags = "微信接口")
@Controller
@RequestMapping("/api/ucenter/wx")
public class WeixinApiController {
//获取微信登录参数
@GetMapping("getLoginParam")
@ResponseBody
public R genQrConnect(HttpSession session) throws UnsupportedEncodingException {
Map<String, Object> map = new HashMap<>();
//地址进行URLEncoder编码
String redirectUri = URLEncoder.encode(ConstantPropertiesUtil.WX_OPEN_REDIRECT_URL, "UTF-8");
map.put("appid", ConstantPropertiesUtil.WX_OPEN_APP_ID);
map.put("redirectUri", redirectUri);
map.put("scope", "snsapi_login");
map.put("state", System.currentTimeMillis()+"");//System.currentTimeMillis()+""
return R.ok().data(map);
}
}3. 修改端口,添加网关配置

#设置路由id
spring.cloud.gateway.routes[4].id=service-user
#设置路由的uri
spring.cloud.gateway.routes[4].uri=lb://service-user
#设置路由断言,代理servicerId为auth-service的/auth/路径
spring.cloud.gateway.routes[4].predicates= Path=/*/ucenter/**2、前端页面实现
(1)方式一,拼写url进行重定向 (重定向到一个网页二维码)
(2)方式二,通过js实现二维码获取(选择,用户体验更好,页面中嵌入二维码)

1. 创建API接口方法
创建 api/wx.js
import request from '@/utils/request'
const api_name = `/api/ucenter/wx`
export default {
getLoginParam() {
return request({
url: `${api_name}/getLoginParam`,
method: `get`
})
}
}2. 确认页面元素

3. 改造JS
import wxApi from '@/api/wx'
...
mounted() {
// 注册全局登录事件对象
window.loginEvent = new Vue();
// 监听登录事件
loginEvent.$on('loginDialogEvent', function () {
document.getElementById("loginDialog").click();
})
// 触发事件,显示登录层:loginEvent.$emit('loginDialogEvent')
//初始化微信js
const script = document.createElement('script')
script.type = 'text/javascript'
script.src = 'https://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js'
document.body.appendChild(script)
// 微信登录回调处理
let self = this;
window["loginCallback"] = (name, token, openid) => {
self.loginCallback(name, token, openid);
}
},
methods: {
//微信登录回调方法
loginCallback(name, token, openid) {
//1.第一次登录,绑定手机号
//2.不是第一次,设置登录状态
},
//切换微信登录
weixinLogin() {
this.dialogAtrr.showLoginType = 'weixin'
wxApi.getLoginParam().then(response => {
let obj = new WxLogin({
self_redirect: true,
id: 'weixinLogin', // 需要显示的容器id
appid: response.data.appid, // 公众号appid wx*******
scope: response.data.scope, // 网页默认即可
redirect_uri: response.data.redirectUri, // 授权成功后回调的url
state: response.data.state, // 可设置为简单的随机数加session用来校验
style: 'black', // 提供"black"、"white"可选。二维码的样式
href: '' // 外部css文件url,需要https
});
});
},
三、微信扫描登录回调接口 - 内网穿透 *
1、内网穿透
外网请求怎么请求到内网地址
解决方案:
1. 在公司中解决内网穿透 *
找运维人员解决,登录交换机控制台,添加内外网的映射关系
例如:192.168.140.100:12345 => 192.168.43.86:8160
2. 个人解决:修改系统配置文件host,添加域名和ip映射
优点:简单
缺点:只能使用80端口,(只能配置ip映射不能配置端口映射)
3. 个人解决:使用内网穿透工具
优点:可以配置ip映射,也可以配合端口映射
缺点:花钱
4. 个人解决:在外网主机上发布web服务,做请求重定向到内网
优势:可以配置ip映射,也可以配合端口映射
缺点:内网的接口url,端口不能修改
5. 个人解决:由微信提供内网穿透,原理和方式 (4) 一致
所以,端口号8160 请求url不能变
1、后端接口开发
1. 接口分析
*参数:code 、state
*返回值:重定向地址
2. userService 添加依赖
<dependencies>
<!--httpclient-->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
</dependencies>3. 添加工具类

4. controller方法实现
//扫码后,微信回调方法,授权临时票据code
@GetMapping("callback")
public String callback(String code, String state, HttpSession session) {
//1.获取微信回调验证码code
System.out.println("code = " + code);
System.out.println("state = " + state);
//2.访问微信接口,用code验证码,换取access_token、open_id
//2.1拼写url
//方式一
String url = "ttps://api.weixin.qq.com/sns/oauth2/access_token?" +
"appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";
//方式二
StringBuffer baseAccessTokenUrl = new StringBuffer()
.append("https://api.weixin.qq.com/sns/oauth2/access_token")
.append("?appid=%s")
.append("&secret=%s")
.append("&code=%s")
.append("&grant_type=authorization_code");
String accessTokenUrl = String.format(baseAccessTokenUrl.toString(),
ConstantPropertiesUtil.WX_OPEN_APP_ID,
ConstantPropertiesUtil.WX_OPEN_APP_SECRET,
code);
//2.2借助工具发送请求获得响应
try {
String accessTokenString = HttpClientUtils.get(accessTokenUrl);
System.out.println("accessTokenString = " + accessTokenString);
//2.3从json串中获取access_token、open_id
JSONObject accessTokenJson = JSONObject.parseObject(accessTokenString);
String accessToken = accessTokenJson.getString("access_token");
String openid = accessTokenJson.getString("openid");
//3.根据open_id查询用户信息
QueryWrapper<UserInfo> wrapper = new QueryWrapper<>();
wrapper.eq("openid",openid);
UserInfo userInfo = userInfoService.getOne(wrapper); //openid是唯一的
//4.用户信息为空,走注册流程
if(userInfo==null){
//5.根据access_token、open_id获取用户信息,完成注册流程
//5.1拼写url
String baseUserInfoUrl = "https://api.weixin.qq.com/sns/userinfo" +
"?access_token=%s" +
"&openid=%s";
String userInfoUrl = String.format(baseUserInfoUrl, accessToken, openid);
//5.2借助工具发送请求,获取响应
String resultInfo = HttpClientUtils.get(userInfoUrl);
System.out.println("resultInfo:"+resultInfo);
//5.3转化返回json串,获取返回值
JSONObject resultInfoJson = JSONObject.parseObject(resultInfo);
//用户昵称
String nickname = resultInfoJson.getString("nickname");
//用户头像
String headimgurl = resultInfoJson.getString("headimgurl");
//5.4userInfo中存入信息,完成注册操作
userInfo = new UserInfo();
userInfo.setOpenid(openid);
userInfo.setNickName(nickname);
userInfo.setStatus(1);
userInfoService.save(userInfo);
}
//6.验证用户是否被锁定
if(userInfo.getStatus()==0){
throw new YyghException(20001,"用户已被锁定");
}
//7.验证用户是否绑定手机号
//如果已绑定手机号openid=""
//如果没有绑定手机号openid=微信唯一编号
Map<String,Object> map = new HashMap<>();
if(userInfo.getPhone()==null){
map.put("openid",openid);
}else {
map.put("openid","");
}
//8.补全用户信息,进行登录
String name = userInfo.getName();
if(StringUtils.isEmpty(name)) {
name = userInfo.getNickName();
}
if(StringUtils.isEmpty(name)) {
name = userInfo.getPhone();
}
String token = JwtHelper.createToken(userInfo.getId(), name);
map.put("token", token);
map.put("name", name);
//9.重定向回相关页面
return "redirect:http://localhost:3000/weixin/callback?token="
+map.get("token")+ "&openid="+map.get("openid")
+"&name="+URLEncoder.encode((String) map.get("name"),"utf-8");
} catch (Exception e) {
e.printStackTrace();
throw new YyghException(20001,"微信扫码登录失败");
}
}5. 改造手机号验证码登录接口,实现绑定手机号
//会员登录
@Override
public Map<String, Object> login(LoginVo loginVo) {
//1.数据校验
String phone = loginVo.getPhone();
String code = loginVo.getCode();
String openid = loginVo.getOpenid();
if(StringUtils.isEmpty(phone)||StringUtils.isEmpty(code)){
throw new YyghException(20001,"注册信息有误");
}
//2.校验验证码
//2.1 根据手机号从redis取出验证码
String rediscode = redisTemplate.opsForValue().get(phone);
//2.2 对比验证码,注意字符串空指针
if(!code.equals(rediscode)){
throw new YyghException(20001,"验证码有误");
}
//2.3判断openid,为空走手机号验证码登录,不为空绑定手机号
Map<String, Object> map = new HashMap<>();
UserInfo userInfo;
if(StringUtils.isEmpty(openid)){
//3.根据手机号查询用户信息
QueryWrapper<UserInfo> wrapper = new QueryWrapper<>();
wrapper.eq("phone",phone);
userInfo = baseMapper.selectOne(wrapper);
//4.用户信息为空,走注册功能
if(userInfo==null){
userInfo = new UserInfo();
userInfo.setPhone(phone);
userInfo.setStatus(1); //0锁定 1正常
baseMapper.insert(userInfo);
}
}else {
//8.根据openid查询用户信息
QueryWrapper<UserInfo> wrapper = new QueryWrapper<>();
wrapper.eq("openid",openid);
userInfo = baseMapper.selectOne(wrapper);
if(userInfo==null){
throw new YyghException(20001,"用户注册信息有误");
}
//9.更新用户手机号信息
userInfo.setPhone(phone);
baseMapper.updateById(userInfo);
}
//5.判断用户是否被锁定
if(userInfo.getStatus()==0){
throw new YyghException(20001,"用户已被锁定");
}
//6.补全用户信息
//返回页面显示名称
String name = userInfo.getName();
if(StringUtils.isEmpty(name)) {
name = userInfo.getNickName();
}
if(StringUtils.isEmpty(name)) {
name = userInfo.getPhone();
}
//7.用户登录
String token = JwtHelper.createToken(userInfo.getId(), userInfo.getName());
map.put("token", token);
map.put("name", name);
return map;
}相关api:

微信名如果是emoji表情,插入数据库会失败。解决方案:java emoji显示乱码_Java处理emoji的方式_雅酷布的博客-CSDN博客
方法2. 添加依赖,进行解析
<!--emoji小图标解析-->
<dependency>
<groupId>com.vdurmont</groupId>
<artifactId>emoji-java</artifactId>
<version>4.0.0</version>
</dependency>
2、整合微信扫描登录前端
1. 需求确认
说明:我们只期望返回一个空页面,然后跟登录层通信就可以了,其实就是一个过渡页面,所以我们要给这个过渡页面定义一个空模板
2. 创建空白布局

3. 创建空白页面

<template>
<!-- header -->
<div>
</div>
<!-- footer -->
</template>
<script>
export default {
layout: "empty",
data() {
return {
}
},
//页面加载后执行
mounted() {
//1.获取参数 query通过问号获取
let token = this.$route.query.token
let openid = this.$route.query.openid
let name = this.$route.query.name
//2.调用父vue方法
window.parent['loginCallback'](name, token, openid)
},
}
</script>4. 在myheader.vue添加方法 微信扫码后方法实现
methods: {
//微信登录回调方法
loginCallback(name, token, openid) {
//1.第一次登录,绑定手机号
if (openid != "") {
this.userInfo.openid = openid
//this.dialogAtrr.showLoginType = 'phone'
this.showLogin() //showLogin 初始化了弹出层对象
}
//2.不是第一次,设置登录状态
this.setCookies(name, token)
},
....
测试:

边栏推荐
- 延迟队列MQ
- [Fun BLDC series with zero basics] Taking GD32F30x as an example, the timer related functions are explained in detail
- 聊聊 MySQL 事务二阶段提交
- Test automation selenium (a)
- iperf3 参数选项详细说明
- 初识Apifox——如何使用Apifox做一个简单的接口测试
- ClickHouse
- Access to display the data
- C language classic practice questions (3) - "Hanoi Tower (Hanoi)"
- 统一异常处理导致ResponseBodyAdvice失效
猜你喜欢

连接mysql报错WARN: Establishing SSL connection without server‘s identity verification is not recommended

九九乘法表

leetcode 剑指 Offer 47. 礼物的最大价值

leetcode 剑指 Offer 15. 二进制中1的个数

Activating data potential Amazon cloud technology reshapes cloud storage "family bucket"

STM32CubeMX配置生成FreeRTOS项目

图像分析:投影曲线的波峰查找

Kotlin 值类 - value class

Explain the problem of change exchange in simple terms - the shell of the backpack problem

PyQt5-在窗口上绘制文本
随机推荐
PyQt5-用像素点绘制正弦曲线
XP电源维修fleXPower电源X7-2J2J2P-120018系列详解
快解析结合任我行crm
LeetCode二叉树系列——94.二叉树的中序遍历
leetcode 剑指 Offer 52. 两个链表的第一个公共节点
Test automation selenium (a)
Jetpack Compose 从入门到入门(八)
Taosi TDengine 2.6+ optimization parameters
leetcode 剑指 Offer 58 - I. 翻转单词顺序
[Fun BLDC series with zero basics] Taking GD32F30x as an example, the timer related functions are explained in detail
编程界的“躲猫猫”比赛 | 每日趣闻
代码随想录笔记_哈希_202 快乐数
快解析结合象过河erp
69. Sqrt(x)x 的平方根
积分简明笔记-第二类曲线积分的类型
PyQt5快速开发与实战 7.4 事件处理机制入门 and 7.5 窗口数据传递
MySQL数据库题库
Unity performance analysis Unity Profile performance analysis tool
2022 Hangzhou Electric Multi-School 2nd Game
20220728 Use the bluetooth on the computer and the bluetooth module HC-05 of Huicheng Technology to pair the bluetooth serial port transmission
