前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >基于若依框架扩展微信扫码登录功能-微信绑定实现

基于若依框架扩展微信扫码登录功能-微信绑定实现

原创
作者头像
薛定喵君
修改2024-10-06 19:55:18
1870
修改2024-10-06 19:55:18
举报
文章被收录于专栏:薛定喵君

前言

最近在学习java相关知识,朋友推荐看一下若依框架,于是在若依框架(前后端分离版)的基础上扩展了一下微信登录功能。

实现思路

标准的扫码登录需要申请微信开放平台账号,并拥有一个已审核通过的网站应用,即:网站应用微信登录,流程比较麻烦。这里为了省事就基于微信公众号网页授权来进行登录操作,同样也可以学习一下扫码登录的流程。

基于公众号网页授权进行扫码登录我们只需要准备一个公众号(需要认证过的服务号或者直接申请测试公众号)。

因为若依框架已经自带了用户表,所以我们这里的扫码登录要拆分成两部分来开发:

  • 若依用户微信绑定
  • 若依用户微信扫码登录

实现过程

微信绑定开发

微信绑定的场景是我们需要先登录若依系统,然后打开个人信息页面,在页面上面点击微信绑定按钮弹出二维码,然后手机微信扫码完成绑定。

绑定部分的扫码流程大致如下:

PC 端点击微信绑定按钮后从当前登录token获取到用户的key,基于用户的key拼接链接在前端弹出一个二维码,二维码地址(附带了生成的用户key)是网页授权链接,微信扫码打开后直接进行公众号网页授权,获取 code 后重定向给后端接口来拿到用户 openid 更新到用户表中完成绑定。

基于此流程结合若依框架我们需要开发如下几个接口并修改页面:

  • 微信openid绑定
  • 用户uuid查询绑定状态及openid
  • 个人信息页追加微信绑定功能

因为需要存取用户微信信息,所以修改代码之前我们需要先向 sys_user 用户表追加两个字段:wx_nick_name、openid。

微信openid绑定开发

1.在ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/下面新建WxController.java用于处理微信相关请求。然后在WxController中追加微信openid绑定方法:

代码语言:java
复制
/**
 * 获取openid
 */
@GetMapping("/bind-openid")
public AjaxResult getOpenid(@RequestParam("code") String code, @RequestParam("key") String key) throws IOException
{
    AjaxResult ajax = AjaxResult.success();
    SysUser u = userService.getOpenid(code);
    String openid = u.getOpenid();
    LoginUser userCache = redisCache.getCacheObject(CacheConstants.LOGIN_TOKEN_KEY + key);
    SysUser user = new SysUser();
    user.setUserId(userCache.getUserId());
    user.setOpenid(openid);
    user.setWxNickName(u.getWxNickName());
    userService.updateUserOpenid(user);

    ajax.put("openid", openid);
    ajax.put("wxnickname", u.getWxNickName());
    return ajax;
}

方法里主要完成了微信公众号授权code的接收,并请求微信接口获取到用户openid,从当前用户登录信息redis缓存中拿到用户id然后把微信用户openid更新到用户表完成绑定。

这里为了方便,直接把code重定向给到了接口地址。

2.在ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java 中追加微信 code 获取用户 openid 方法:

代码语言:java
复制
/**
 * 通过code获取用户openid
 *
 * @param code 微信公众号网页授权码
 * @return 用户openid
 */
@Override
public SysUser getOpenid(String code) {
    RestTemplate restTemplate = new RestTemplate();
    JSONObject jsonData = null;

    // 构建获取access_token的URL
    String url = "https://api.weixin.qq.com/sns/oauth2/access_token?"
            + "appid=" + appId
            + "&secret=" + secret
            + "&code=" + code
            + "&grant_type=authorization_code";

    System.out.println("url: " + url);
    ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class);

    System.out.println("responseEntity: " + responseEntity);
    if (responseEntity.getStatusCodeValue() == 200 && responseEntity.getBody() != null) {
        jsonData = JSONObject.parseObject(responseEntity.getBody());
    }

    String userInfoUrl = "https://api.weixin.qq.com/sns/userinfo?lang=zh_CN"
            + "&access_token=" + jsonData.getString("access_token")
            + "&openid=" + jsonData.getString("openid");

    ResponseEntity<String> responseUserEntity = restTemplate.getForEntity(userInfoUrl, String.class);
    if (responseUserEntity.getStatusCodeValue() == 200 && responseUserEntity.getBody() != null) {
        JSONObject jsonUserData = JSONObject.parseObject(new String(responseUserEntity.getBody().getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8));
        System.out.println("jsonUserData: " + jsonUserData);
        SysUser user = new SysUser();
        user.setOpenid(jsonUserData.getString("openid"));
        user.setWxNickName(jsonUserData.getString("nickname"));
        return user;
    }

    return null;
}

因为这里用到了公众号appid和secret,所以我们要在 ruoyi-admin/src/main/resources/application.yml 配置文件中追加相应配置:

代码语言:yml
复制
# 公众号配置
wechat:
  # 应用ID
  appid:
  # 应用密钥
  secret:

追加配置之后需要在 SysUserServiceImpl 中补充对应私有属性:

代码语言:java
复制
@Value("${wechat.appid}")
private String appId;

@Value("${wechat.secret}")
private String secret;

3.在ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java中追加修改用户openid的方法:

代码语言:java
复制
/**
 * 修改用户openid
 *
 * @param user 用户信息
 * @return 结果
 */
@Override
public int updateUserOpenid(SysUser user)
{
    return userMapper.updateUser(user);
}

这里需要我们在 ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java 中追加对应的方法声明:

代码语言:java
复制
/**
 * 修改用户信息
 * 
 * @param user 用户信息
 * @return 结果
 */
public int updateUser(SysUser user);

并且在 ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml 中补充更新对应的sql,即向更新用户sql的set部分追加微信openid及昵称的更新判断:

代码语言:xml
复制
<update id="updateUser" parameterType="SysUser">
 	...
	<if test="openid != null and openid != ''">openid = #{openid},</if>
	<if test="wxNickName != null and wxNickName != ''">wx_nick_name = #{wxNickName},</if>
	...
</update>

因为新增了微信openid及昵称的信息,所以需要修改一下ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java文件,追加微信昵称及openid属性:

代码语言:java
复制
/** 用户微信昵称 */
@Excel(name = "用户微信昵称")
private String wxNickName;

/** openid */
@Excel(name = "openid")
private String openid;

public String getOpenid()
{
    return openid;
}

public void setOpenid(String openid)
{
    this.openid = openid;
}

public String getWxNickName()
{
    return wxNickName;
}

public void setWxNickName(String wxNickName)
{
    this.wxNickName = wxNickName;
}

这样我们就完成了微信openid绑定接口的开发。

用户uuid查询绑定状态及openid

下面就是要查询微信绑定的信息了。

1.在ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/WxController.java中追加户uuid查询openid方法:

代码语言:java
复制
/**
 * 已登录用户uuid查询openid
 */
@GetMapping("/uuid")
public AjaxResult getCode(@RequestParam("uuid") String uuid) throws IOException
{
    AjaxResult ajax = AjaxResult.success();
    LoginUser userLogin = redisCache.getCacheObject(CacheConstants.LOGIN_TOKEN_KEY + uuid);
    SysUser user = userService.selectUserById(userLogin.getUserId());
    System.out.println("user-openid: " + user.getOpenid());
    System.out.println("user-wxnickname: " + user.getWxNickName());
    if (user.getOpenid() != null) {
        ajax.put("openid", user.getOpenid());
        ajax.put("wxnickname", user.getWxNickName());
    }
    ajax.put("status", user.getOpenid() != null ? 1: 0);
    return ajax;
}

2.在ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml的selectUserVo查询sql中追加openid、微信昵称查询:

代码语言:xml
复制
<sql id="selectUserVo">
select  ...,
        u.openid, u.wx_nick_name,
        ...
        from sys_user u
</select>

这样查询到的用户信息里面就会包含绑定的微信信息了。

接口访问权限修改

因为扫码绑定的时候用户在手机上是没有登录的所有要在 ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java 中把绑定接口加入到允许列表中:

代码语言:java
复制
requests.antMatchers("/login", "/register", "/captchaImage", "/bind-openid").permitAll()

到这里绑定需要开发的接口就修改完了,我们接着来修改页面。

个人信息页追加微信绑定
  1. 前端项目依赖追加。因为扫码需要生成二维码,所以这里为了方便使用前端插件vue-qr生成,在前端项目根目录npm install vue-qr即可。
  2. 追加接口。在ruoyi-ui/src/api/system/user.js中追加我们上面写好的查询绑定状态接口:
代码语言:js
复制
export function getUUid(data) {
    return request({
        url: '/uuid?uuid=' + data.uuid,
        method: 'get'
    })
}

3.页面修改。修改个人信息页ruoyi-ui/src/views/system/user/profile/userInfo.vue

3.1 增加微信绑定按钮及弹窗:

代码语言:html
复制
<el-form-item label="微信">
    <span class="mr10">{{form.wxnickname || '未绑定'}}</span>
    <el-button v-if="form.openid == '' || form.openid == null" :loading="bindloading" size="medium" type="primary" class="btn" @click.stop="wxBind()">绑 定</el-button>
    <el-button v-else :loading="bindloading" size="medium" type="primary" class="btn" @click.stop="unBind()">解
        绑</el-button>
</el-form-item>

<el-dialog title="绑定微信" custom-class="bind-dialog" class="new-common-dialog" :visible.sync="bindWxVisible" :close-on-click-modal="false" :close-on-press-escape="false" @close="wxLoginClose" width="320px">
    <div class="qr-code">
        <vue-qr :text="qrUrl" :size="280"></vue-qr>
    </div>
</el-dialog>

3.2 导入依赖接口及相关方法:

代码语言:js
复制
import {
    updateUserProfile,
    getUUid
} from "@/api/system/user";
import {
    getToken
} from '@/utils/auth'
import vueQr from 'vue-qr'

3.3 引用二维码组件:

代码语言:js
复制
components: {
    vueQr,
},

3.4 data中新增属性:

代码语言:js
复制
timer: null,
    bindWxVisible: false,
    bindloading: false,
    qrUrl: '',

3.5 修改user监听方法,使页面能够回显微信昵称:

代码语言:js
复制
user: {
    handler(user) {
        console.log('user', this.user)
        if (user) {
            this.form = {
                nickName: user.nickName,
                wxnickname: user.wxNickName,
                phonenumber: user.phonenumber,
                email: user.email,
                sex: user.sex,
                openid: user.openid
            };
        }
    },
    immediate: true
}

3.6 增加微信绑定相关方法:

代码语言:js
复制
 wxBind() {
    let token = getToken()
    const key = JSON.parse(atob(token.split('.')[1]))['login_user_key'];
    const redirect_uri = `http://web-hub.uat.kai12.cn/auth.html?backUrl=${本机IP}:8080/bind-openid?key=${key}`
    const codeUrl = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=公众号appid&redirect_uri=${encodeURIComponent(redirect_uri)}&response_type=code&scope=snsapi_userinfo&state=123456#wechat_redirect`
    this.qrUrl = codeUrl
    console.log(this.qrUrl)
    this.bindWxVisible = true
    let that = this
    this.timer = setInterval(function() {
        getUUid({
                uuid: key
            })
            .then((res) => {
                console.log(res)
                if (res.status === 1) {
                    that.bindWxVisible = false
                    that.form.openid = res.openid
                    that.form.wxnickname = res.wxnickname
                    that.$message({
                        type: 'success',
                        message: '操作成功',
                    })
                    clearTimeout(this.timer)
                }
            })
            .catch((err) => {
                clearTimeout(that.timer)
            })
    }, 1000)
},
wxLoginClose() {
    this.timer && clearTimeout(this.timer)
},

这里主要是通过获取浏览器缓存的token,从中解析出若依用户的 login_user_key 来实现关联绑定的。

然后整个微信绑定流程就大致完成了。

测试一下:

参考资料

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 实现思路
  • 实现过程
    • 微信绑定开发
      • 微信openid绑定开发
      • 用户uuid查询绑定状态及openid
      • 接口访问权限修改
      • 个人信息页追加微信绑定
  • 参考资料
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档