⛰️个人主页: 蒾酒
🔥系列专栏:《spring boot实战》
🌊山高路远,行路漫漫,终有归途
目录
写在前面
登录流程
流程解析
具体实现
相关代码
说明
服务端
小程序端
写在最后
写在前面
本文介绍了springboot开发微信小程序后端服务中,用户登录功能的设计与实现,坚持看完相信对你有帮助。
同时欢迎订阅springboot系列专栏,持续分享spring boot的使用经验。
登录流程
如图:
这是微信官方文档中微信小程序登录的流程时序图,我在图中红色序号标注的五步就是完整的微信小程序登录流程。
流程解析
- 小程序端通过
wx.login()
获取用户登录凭证code。- 小程序将code发送到服务端的登录接口。
- 服务端的登录接口使用该code、小程序的AppID和AppSecret向微信服务器发起请求,获取用户的openid。
- 服务端拿到openid后,可以根据业务需求生成用户令牌(Token),通常包括用户信息、权限等,并返回给小程序。
- 小程序在本地缓存该用户令牌。
- 后续小程序发起请求时,在请求头中携带该用户令牌(Token)。
- 服务端接收到请求时,验证用户令牌的有效性,确保用户是经过认证和授权的。
具体实现
登录接口设计思路
- 接收小程序端传递的code参数。
- 使用code、小程序的AppID和AppSecret向微信服务器发起请求,获取用户的openid。
- 在数据库用户表中查询是否存在该openid。
- 如果存在该openid,则使用查询到的用户信息生成令牌(Token)。
- 如果不存在该openid,则进行用户注册操作,将新用户信息插入数据库用户表,并生成令牌(Token)。
- 返回生成的令牌(Token)给小程序端。
相关代码
说明
下面代码基于jdk17,发请求用的时jdk自带的http工具类,如果你的jdk版本低于11,可以使用okhttp依赖来发请求,然后jwt相关工具类代码在我本专栏的其他文章里面,用到的ORM框架为mybatis-plus整合相关代码也在本专栏。
服务端
登录dto
@Data
public class UserLoginDTO {
@NotBlank(message = "code不能为空")
private String code;
private Map<String,Object> userInfo;//用户完善信息
}
登录返回vo
@Data
@Builder
public class UserLoginVO implements Serializable {
private Long id; //用户id
private String openid;//用户在小程序唯一标识
private String token;//用户登录凭证
}
获取openid方法
使用的是jdk17自带的HttpClient,也可以使用okhttp,或者糊涂工具包里面的。
private String getOpenid(String code) {
HttpClient httpClient = HttpClient.newHttpClient();
// 构建请求参数字符串
String params = String.format("appid=%s&secret=%s&js_code=%s&grant_type=%s",
URLEncoder.encode(wxMiniConfig.getAppId(), StandardCharsets.UTF_8),
URLEncoder.encode(wxMiniConfig.getAppSecret(), StandardCharsets.UTF_8),
URLEncoder.encode(code, StandardCharsets.UTF_8),
URLEncoder.encode("authorization_code", StandardCharsets.UTF_8));
// 创建 GET 请求
String url = "https://api.weixin.qq.com/sns/jscode2session?" + params;
HttpRequest httpRequest = HttpRequest.newBuilder()
.uri(URI.create(url))
.build();
try {
// 发送 GET 请求
HttpResponse<String> httpResponse = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
// 获取响应结果
int statusCode = httpResponse.statusCode();
String responseBody = httpResponse.body();
JSONObject responseJson = JSONObject.parseObject(responseBody);
String openid = responseJson.getString("openid");
// 处理响应结果
System.out.println("状态代码: " + statusCode);
System.out.println("响应正文: " + responseBody);
return openid;
} catch (Exception e) {
log.error("发送请求时出错: {}", e.getMessage());
return null;
}
}
登录逻辑代码
在判断出是新用户时,进行注册操作还需要将请求携带过来的userInfo完善信息,用户名,头像等一同封装进User对象再插入到数据库这里我就省略了
@Override
public UserLoginVO login(UserLoginDTO userLoginDTO) {
//获取openid
String openid = getOpenid(userLoginDTO.getCode());
if(StringUtils.isBlank(openid)){
throw new GeneralBusinessException(ResultEnum.USER_OPENID_ERROR); // openid获取失败
}
User user = new LambdaQueryChainWrapper<>(userMapper).eq(User::getOpenid, openid).one();
if(Objects.isNull(user)){
// 用户不存在则注册
user = new User();
//获取完善信息,用户呢称、头像url
userLoginDTO.getUserInfo
//封装信息。。。。。。
//。。。。。。。。。。
user.setOpenid(openid);
// 注册用户
if(!this.save(user)){
throw new GeneralBusinessException(ResultEnum.USER_REGISTER_FAIL); // 用户注册失败
}
}
return UserLoginVO.builder()
.id(user.getUserId())
.openid(user.getOpenid())
.token(jwtUtils.generateToken(Map.of("userId", user.getUserId()), "user"))
.build();
}
小程序端
如图点击登录按钮会进行登录(注册)
wxml:
<button bindtap="handleLogin">登录</button>
js:
// 点击登录按钮时触发的方法
handleLogin: function() {
// 调用微信登录接口获取 code
wx.login({
success: res => {
const code = res.code;
if (code) {
// 调用微信登录接口获取用户信息
wx.getUserProfile({
desc: '用于完善会员资料',
success: res => {
const userInfo = res.userInfo;
// 将 code 和用户信息发送到后端服务器进行登录验证
wx.request({
url: 'http://localhost:8080/user/login',
method: 'POST',
data: {
code: code,
userInfo: userInfo
},
success: res => {
const { token } = res.data; // 假设后端返回包含 token 的数据
if (token) {
// 登录成功,保存 token到本地存储
wx.setStorageSync('token', token);
// 跳转到主页或其他页面
wx.navigateTo({
url: '/pages/home/home'
});
} else {
// 登录失败,显示提示信息
wx.showToast({
title: '登录失败,请重试',
icon: 'none'
});
}
},
fail: err => {
console.error('登录请求失败', err);
}
});
},
fail: err => {
console.error('获取用户信息失败', err);
}
});
} else {
console.error('获取登录凭证失败', res.errMsg);
}
},
fail: err => {
console.error('调用登录接口失败', err);
}
});
}
补充:实际开发中不会直接使用wx.request进行登录请求,一般都会进行封装,这里作为演示我就直接使用了,实际发送的post请求,请求体会携带code,和用户昵称、头像路径等信息。
写在最后
本文完整的介绍了springboot开发微信小程序服务端中用户登录功能的设计思路,希望对你有帮助。