一.大致实现思路
1.给微信图标绑定一个触发事件,实现微信登录,然后再调用小程序的API。
2.调用wx.getUserProfile()方法,这个方法是微信自带的,关于是否微信获取用户信息的权限。
3.用户同意后,在wx.getUserProfile()的回调中再次调用wx.login()这个API。会返回一个code 这个code每次调用都会刷新一次,(注意:不能携带code进行两次请求,否则会报错,40029)
4. 然后前端发送请求携带code到后端,你也可以携带用户信息对象,在下面代码会演示。
5.后端开始根据这个code和你的小程序的AppId和Appsecret调用微信的服务器来获得openId(这是每个用户登录的唯一id,后期可以根据openid查询登录信息,而不会重复)
6.获取到openid后就可以进行自定义业务逻辑了。
二.下面开始演示代码
前端:uniapp
2.1 首先给微信图标绑定事件
<image @click="weixinLo()" class="icon" src="../../static/微信.png" ></image>
2.2 js代码:主要思路:
1.主要逻辑是先判断是否含有token,这个是验证登录的标识
2.判断是否用户收授权登录
3.用户同意后调用wx.login()方法,返回code和登录对象信息返回给后端接口。
weixinLo(){
let that = this
let token = uni.getStorageSync('token')
wx.showLoading({
title: '加载中',
})
console.log(token)
if(token){
//如果已经有token,说明用户已经登录,跳转到指定页面
wx.reLaunch({
url: "../index/index"
})
}else{
// 未登录
wx.getUserProfile({
desc: '用于完善用户资料',
success(res) {
that.userInfo = res.userInfo
if (res.errMsg == "getUserProfile:ok") {
let code = null
wx.login({
success(e) {
code = e.code
let params = {};
params.code = code; //用户code 注:用户的code每次登录都是随机的,所以不需要进行存储
params.avatar = res.userInfo.avatarUrl; //用户头像
params.nickname = res.userInfo.nickName; //用户微信名
params.sex = res.userInfo.gender; //用户性别 0为未知,1为男,2为女
wx.request({
url: 'http://localhost:8010/educmsl/api/ucenterstu/wx/login',
method: 'POST',
data: params,
success(res) {
if(res.data.success){
//存储用户信息
uni.setStorageSync('token', res.data.data.token);
uni.reLaunch({
url: '../my/my'
})
}else{
console.log(res.data.message)
}
}
})
}
})
}
}
})
}
},
后端: java
2.3. 写接口先得预备工作,先获得小程序的appid与密钥
主要思路: 创建一个获取小程序appid与密钥的类
实现步骤: 通过springboot的组件@Component注解,然后类实现 InitializingBean 这个接口(是用来初始化bean对象的作用)。
注意:这里使用了@Component注解,最好在启动类上加上 @ComponentScan(basePackages={"com.laoyang"})这个注解,用来扫描我们自己的组件。
package com.laoyang.educms.utils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* @author:Kevin
* @create: 2022-11-03 15:00
* @Description: 小程序密钥与id
*/
@Component
public class Wxmini implements InitializingBean {
@Value("${wxMini.appId}")
private String appid;
@Value("${wxMini.secret}")
private String secret;
public static String APPID;
public static String SECRET;
@Override
public void afterPropertiesSet() throws Exception {
APPID = appid;
SECRET = secret;
}
}
2.3.1:然后还要在配置文件添加appid与密钥
2.4:主要接口开发
主要思路:
1. 后台接收到前端的code,然后携带appid和密钥发送请求到微信的服务器。
2. 然后响应获得openid,实现自定义逻辑,说下我的逻辑。
3. 先new用户对象,将前端授权获得的信息封装到此对象中,然后根据opendi查询是否有这个对象,有就执行更新信息操作,没有就添加信息。然后生成token返回给前端。
https://api.weixin.qq.com/sns/jscode2session?appid=" + Wxmini.APPID + "&secret=" + Wxmini.SECRET + "&js_code=" + code + "&grant_type=authorization_code";
package com.laoyang.educms.controller;
import com.alibaba.fastjson.JSONObject;
import com.laoyang.CommonUtils.JwtUtils;
import com.laoyang.CommonUtils.R;
import com.laoyang.educms.entity.UcenterMember;
import com.laoyang.educms.service.UcenterMemberService;
import com.laoyang.educms.utils.WeChatUtil;
import com.laoyang.educms.utils.Wxmini;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Date;
/**
* @author:Kevin
* @create: 2022-11-03 12:26
* @Description: 微信小程序登录与退出
*/
@RestController //注意这里没有配置 @RestController
@RequestMapping("/educmsl/api/ucenterstu/wx")
public class WxApiStuController {
@Autowired
private UcenterMemberService memberService;
@PostMapping("/login")
public R wxlogin(@RequestBody UcenterMember user){
String code = user.getCode();
if (code == "" || "".equals(code)){
return R.error("code不能为空!");
}else {
//微信接口服务,通过调用微信接口服务中jscode2session接口获取到openid和session_key
String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + Wxmini.APPID + "&secret=" + Wxmini.SECRET + "&js_code=" + code + "&grant_type=authorization_code";
String str = WeChatUtil.httpRequest(url, "GET", null); //调用工具类解密
JSONObject jsonObject= JSONObject.parseObject(str);
String openid = (String) jsonObject.get("openid");
if(openid != null && !"".equals(openid)){
//登录成功
UcenterMember member = new UcenterMember();
member.setNickname(user.getNickname());
member.setOpenid(openid);
member.setAvatar(user.getAvatar());
member.setGmtCreate(new Date());
member.setGmtModified(new Date());
UcenterMember mymember = memberService.getByOPenId(openid);
if (mymember == null){
//就是第一次登录,向数据库插入信息
//向数据库中插入一条记录
memberService.save(member);
}else {
//更新数据
member.setId(mymember.getId());
memberService.updateById(member);
}
//使用jwt生成token,
String jwtToken = JwtUtils.getJwtToken(member.getId(), member.getNickname());
return R.ok().data("token",jwtToken);
}
}
return R.error("登录失败");
}
}
小结:
首先说下我开发中遇到的问题,希望大家避坑,
1.在写Controller时没有添加@RestController,返回前端json格式的注解,所以刚开始时后台响应成功了,前端却报404.
2.code因为是一次性的,所以不能在请求里的请求携带code,否则微信服务器会响应40029的报错代码信息。因此就在wx.login()的回调函数中请求后端接口并携带code就ok了。