一、公众号环境搭建
本篇文章使用的虽然是微信公众号测试号,正式公众号同理,也需要下面几个步骤,只是说每个操作多了一次管理员扫码校验而已
-
测试号申请地址:https://mp.weixin.qq.com/debug/cgi-bin/sandboxinfo?action=showinfo&t=sandbox/index,拿到 appID、appsecret 两个配置
修改里面的域名信息,填写的是域名,不需要 http,直接写域名

二、Spring Boot 集成微信公众号
1、application.yml 微信配置
# 微信配置
business:
baseUrl: https://tellsea.4kb.cn
appUserUrl: http://192.168.3.6:8081/gyplay-app-user/#
weixin:
appId: 上面获取的公众号appId
secret: 上面获取的公众号secret
# 微信授权登录回调
callBackUrl: ${business.baseUrl}/gyplay-service/au/weiXin/callBack
# 重定向到登录页
redirectLoginUrl: ${business.appUserUrl}/pages/login/login
为了方便获取配置文件的内容,这里读取配置信息使用的是 @ConfigurationProperties 注解的方式
package com.ruoyi.business.appuser.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @author Tellsea
* @date 2022/8/22
*/
@Data
@Component
@ConfigurationProperties(prefix = "business.weixin")
public class WeiXinProperties {
private String appId;
private String secret;
/**
* 微信授权登录回调
*/
private String callBackUrl;
/**
* 重定向到登录页
*/
private String redirectLoginUrl;
}
2、控制层接口
然后增加一个微信相关的控制器,里面有两个方法
-
微信授权登录,返回前端调用的连接 -
用户授权登录成功之后的回调地址请求接口,重定向到前端页面
还有最后一个流程就是前端页面根据登录授权信息,比如 token 换取用户信息等,这就是整个授权登录流程
控制层代码如下
package com.ruoyi.business.appuser.controller;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.business.appuser.config.WeiXinProperties;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginBody;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.exception.CustomException;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.framework.web.service.SysLoginService;
import com.ruoyi.framework.web.service.SysPermissionService;
import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.system.domain.SysUserRole;
import com.ruoyi.system.mapper.SysUserRoleMapper;
import com.ruoyi.system.service.ISysUserService;
import com.zhhy.consts.RoleConstants;
import com.zhhy.tool.utils.IntegerUtils;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* @author Tellsea
* @date 2021/07/01
*/
@RestController
@RequestMapping("/au/weiXin")
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class AuWeiXinController {
private final ISysUserService userService;
private final SysPermissionService permissionService;
private final TokenService tokenService;
private final SysUserRoleMapper sysUserRoleMapper;
private final SysLoginService loginService;
private final WeiXinProperties weiXinProperties;
@ApiOperation("微信授权登录")
@GetMapping("login")
public AjaxResult login() {
try {
String redirect_uri = URLEncoder.encode(weiXinProperties.getCallBackUrl(), "UTF-8");
String url = "https://open.weixin.qq.com/connect/oauth2/authorize?"
+ "appid=" + weiXinProperties.getAppId()
+ "&redirect_uri=" + redirect_uri
+ "&response_type=code"
+ "&scope=snsapi_userinfo"
+ "&state="
+ "&connect_redirect=1#wechat_redirect";
return AjaxResult.success("请求成功", url);
} catch (Exception e) {
e.printStackTrace();
return AjaxResult.error("微信授权登录失败");
}
}
@ApiOperation("回调地址")
@GetMapping("callBack")
public void callBack(HttpServletRequest request, HttpServletResponse response) {
String code = request.getParameter("code");
String state = request.getParameter("state");
String url = "https://api.weixin.qq.com/sns/oauth2/access_token?"
+ "appid=" + weiXinProperties.getAppId()
+ "&secret=" + weiXinProperties.getSecret()
+ "&code=" + code
+ "&grant_type=authorization_code";
JSONObject jsonObject = JSON.parseObject(HttpUtil.get(url));
Integer errcode = jsonObject.getInteger("errcode");
if (errcode != null) {
String errmsg = jsonObject.getString("errmsg");
throw new CustomException("【微信回调错误】错误码:" + errcode + ",错误信息:" + errmsg);
}
String openid = jsonObject.getString("openid");
String access_token = jsonObject.getString("access_token");
String refresh_token = jsonObject.getString("refresh_token");
Integer expires_in = jsonObject.getInteger("expires_in");
String infoUrl = "https://api.weixin.qq.com/sns/userinfo?"
+ "access_token=" + access_token
+ "&openid=" + openid
+ "&lang=zh_CN";
// 获取微信用户信息
JSONObject userInfo = JSON.parseObject(HttpUtil.get(infoUrl));
String country = userInfo.getString("country");
String province = userInfo.getString("province");
String city = userInfo.getString("city");
Integer sexValue = userInfo.getInteger("sex");
String nickName = userInfo.getString("nickname");
String avatar = userInfo.getString("headimgurl");
String language = userInfo.getString("language");
String sex;
if (IntegerUtils.eq(sexValue, 1)) {
sex = "0";
} else if (IntegerUtils.eq(sexValue, 2)) {
sex = "1";
} else {
sex = "2";
}
List<SysUser> list = userService.list(new LambdaQueryWrapper<SysUser>().eq(SysUser::getOpenId, openid));
String token;
SysUser user = null;
if (CollectionUtils.isEmpty(list)) {
// 注册用户
SysUser entity = new SysUser();
entity.setOpenId(openid);
entity.setUserName(openid);
entity.setNickName(nickName);
entity.setAvatar(avatar);
entity.setDeptId(0L);
entity.setSex(sex);
entity.setRoleIds(new Long[]{RoleConstants.USER.getRoleId()});
userService.insertUser(entity);
SysUser sysUser = userService.selectUserByUserName(entity.getUserName());
LoginUser loginUser = new LoginUser(sysUser, permissionService.getMenuPermission(sysUser));
token = tokenService.createToken(loginUser);
} else if (list.size() == 1) {
// 更新用户
user = list.get(0);
user.setNickName(nickName);
userService.updateById(user);
SysUser sysUser = userService.selectUserByUserName(user.getUserName());
List<SysRole> roles = sysUser.getRoles();
List<String> roleKeys = roles.stream().map(SysRole::getRoleKey).collect(Collectors.toList());
if (!roleKeys.contains(RoleConstants.USER.getRoleKey())) {
// 给角色用户
sysUserRoleMapper.insert(new SysUserRole().setUserId(user.getUserId()).setRoleId(RoleConstants.USER.getRoleId()));
sysUser = userService.selectUserByUserName(user.getUserName());
}
LoginUser loginUser = new LoginUser(sysUser, permissionService.getMenuPermission(sysUser));
token = tokenService.createToken(loginUser);
} else {
throw new CustomException("数据异常:OpenId存在多个");
}
try {
// 重定向到登录,自动跳转首页
String redirectUrl = weiXinProperties.getRedirectLoginUrl() + "?token=" + token;
response.sendRedirect(redirectUrl);
} catch (IOException e) {
e.printStackTrace();
throw new CustomException("【微信回调错误】重定向地址错误");
}
}
@ApiOperation("获取用户信息")
@GetMapping("getInfo")
public AjaxResult getInfo() {
LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
SysUser user = loginUser.getUser();
Set<String> permission = permissionService.getRolePermission(user);
AjaxResult ajax = AjaxResult.success();
ajax.put("user", user);
ajax.put("roles", permission);
ajax.put("permissions", permissionService.getMenuPermission(user));
return ajax;
}
}
三、Uniapp 实现授权登录
前端点击登录,获取授权链接,然后访问连接授权,拿到 token 信息,然后使用 token 换取用户信息,放入缓存中,并修改请求工具类的请求拦截器,没有拦截器的,直接判断缓存是否有 token,有就添加到请求头中,因为后台通常都是从 header 里面获取 token 进行校验的
<template>
<view class="container">
<image src="/static/images/wx-login.jpeg"></image>
<view>申请获取以下权限</view>
<view>获得你的公开信息(昵称,头像、地区等)</view>
<view>获得你微信绑定的手机号</view>
<u-button type="primary" size="default" class="login-btn" @tap="login">
微信授权登录
</u-button>
</view>
</template>
<script>
let that;
export default {
data() {
return {
}
},
onLoad(option) {
that = this;
let token = option.token;
if (that.$validator.isNotEmpty(token)) {
// 登录成功回调
uni.setStorageSync(that.$config.cachePrefix + 'token', token);
uni.$u.http.get('/au/weiXin/getInfo').then(res => {
uni.setStorageSync(that.$config.cachePrefix + 'user', res.user);
uni.setStorageSync(that.$config.cachePrefix + 'role', res.role);
uni.setStorageSync(that.$config.cachePrefix + 'permissions', res.permissions);
});
}
},
methods: {
login() {
uni.$u.http.get('/au/weiXin/login').then(res => {
if (res.code == 200) {
window.location.href = res.data;
} else {
that.$msg(res.msg);
}
});
}
},
}
</script>
<style lang="scss" scoped>
page {
background-color: white;
}
.container {
font-size: 13px;
color: $u-main-color;
line-height: 25px;
padding: 100px 20px;
height: 100vh;
image {
width: 60px;
height: 50px;
margin-left: calc((100% - 60px) / 2);
}
.login-btn {
margin-top: 50px;
}
}
</style>
我这里使用的是 uview2.x,是有一个 util/request/requestInterceptors.js 请求拦截器的,只需要增加一个 token 校验就行了相关代码这里粘贴如下
import $config from '@/common/config.js';
import {validator} from '@/common/validator.js';
/**
* 请求拦截
* @param {Object} http
*/
module.exports = (vm) => {
uni.$u.http.interceptors.request.use((config) => { // 可使用async await 做异步操作
// 初始化请求拦截器时,会执行此方法,此时data为undefined,赋予默认{}
config.data = config.data || {};
let token = uni.getStorageSync($config.cachePrefix + 'token');
// header: {
// 'content-type': 'application/json',
// 'Authorization': validator.isEmpty(token) ? '' : 'Bearer ' + token
// },
config.header.Authorization = validator.isEmpty(token) ? '' : 'Bearer ' + token;
// 可以在此通过vm引用vuex中的变量,具体值在vm.$store.state中
// console.log(vm.$store.state);
return config
}, (config) => // 可使用async await 做异步操作
Promise.reject(config))
}
检查一下数据库,OpenId、头像、昵称、性别这些全部都是有的
到此,SpringBoot 集成 Uniapp 实现微信公众号授权登录完成了
原文始发于微信公众号(花海里):【SpringBoot学习】46、SpringBoot 集成 Uniapp 实现微信公众号授权登录
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/69541.html