【SpringBoot学习】46、SpringBoot 集成 Uniapp 实现微信公众号授权登录

一、公众号环境搭建

本篇文章使用的虽然是微信公众号测试号,正式公众号同理,也需要下面几个步骤,只是说每个操作多了一次管理员扫码校验而已


然后下一步,关注自己的测试号,否则无法授权登录


继续修改网页授权配置


修改里面的域名信息,填写的是域名,不需要 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("beforeLogin")
    public AjaxResult beforeLogin() {
        return AjaxResult.success("检查成功");
    }
   
    @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 实现微信公众号授权登录完成了

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Tellsea

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值