上一次我们在若依框架的基础上扩展了微信绑定的功能,下面我们接着来实现扫码登录。
PC 端点击微信登录时生成一个 uuid 存入 redis 并弹出一个二维码,二维码地址(附带了生成的 uuid)是移动端的网页,微信扫码后打开的是配置好的网页授权链接,通过网页授权的方式获取 code 拿到用户 openid 后存入redis中,PC 端通过轮询方式根据生成的 uuid 查询用户 openid 进行登录。
基于以上实现思路结合若依框架需要开发如下几个接口并修改页面:
在 ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/WxController.java
中追加uuid 生成方法:
/**
* 扫码登录用uuid生成
*/
@GetMapping("/uuid/get")
public AjaxResult getUUID() throws IOException
{
AjaxResult ajax = AjaxResult.success();
String uuid = IdUtils.simpleUUID();
String verifyKey = CacheConstants.WX_OPENID_KEY + uuid;
redisCache.setCacheObject(verifyKey, null, 1, TimeUnit.MINUTES);
ajax.put("uuid", uuid);
return ajax;
}
方法里主要利用若依自带的方法生成UUID并存储到redis里(有效期设置为1分钟),需要在 ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java
中增加一个 WX_OPENID_KEY
常量用于存放openid:
/**
* 微信openid redis key
*/
public static final String WX_OPENID_KEY = "wx_openid:";
同样的,在 WxController.java
中追加uuid绑定用户openid的方法:
/**
* uuid绑定openid
*/
@GetMapping("/uuid/bind/openid")
public AjaxResult bindOpenid(@RequestParam("code") String code, @RequestParam("uuid") String uuid) throws IOException
{
AjaxResult ajax = AjaxResult.success();
SysUser user = userService.getOpenid(code);
String openid = user.getOpenid();
String wxNickName = user.getWxNickName();
String verifyKey = CacheConstants.WX_OPENID_KEY + uuid;
long expire = redisCache.getExpire(verifyKey);
redisCache.setCacheObject(verifyKey, openid);
if (expire > 0) {
redisCache.expire(verifyKey, expire, TimeUnit.SECONDS);
}
ajax.put("openid", openid);
ajax.put("wxNickName", wxNickName);
return ajax;
}
该方法用于微信扫码时接收微信重定向过来的code以及点击扫码登录时产生的随机UUID,调用上一篇中 SysUserServiceImpl
追加的 getOpenid
方法获取到用户的openid和微信昵称,并把openid更新到对应UUID的redis缓存中。
在 WxController.java
中继续追加UUID登录方法:
/**
* uuid登录
*/
@GetMapping("/uuid/login")
public AjaxResult loginByOpenId(@RequestParam("uuid") String uuid) throws IOException
{
AjaxResult ajax = AjaxResult.success();
String verifyKey = CacheConstants.WX_OPENID_KEY + uuid;
String openid = redisCache.getCacheObject(verifyKey);
ajax.put("status", 0);
System.out.println("openid:{}" + openid);
if(openid != null) {
SysUser user = userService.selectUserByOpenId(openid);
System.out.println("用户:{}" + user);
if (user == null)
{
System.out.println("用户不存在");
return error("用户不存在");
}
LoginUser loginUser = new LoginUser(user.getUserId(), user.getDeptId(), user, permissionService.getMenuPermission(user));
// 生成token
String token = tokenService.createToken(loginUser);
ajax.put("token", token);
ajax.put("status", 1);
redisCache.deleteObject(verifyKey);
}
return ajax;
}
该方法用于在前端轮询随机生成的UUID,如果在缓存中查询到 openid
就使用 openid
查询用户信息,所以需要在 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java
中补充通过openid查询用户的方法:
/**
* 通过openid查询用户
*
* @param openId 用户名
* @return 用户对象信息
*/
@Override
public SysUser selectUserByOpenId(String openId)
{
return userMapper.selectUserByOpenId(openId);
}
同时要在ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java
中追加对应的方法声明:
/**
* 通过openId查询用户
*
* @param openId openid
* @return 用户对象信息
*/
public SysUser selectUserByOpenId(String openId);
并且在 ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml
中补充对应的查询sql,根据微信openid获取用户:
<select id="selectUserByOpenId" parameterType="String" resultMap="SysUserResult">
<include refid="selectUserVo"/>
where u.openid = #{openid} and u.del_flag = '0'
</select>
如果能查询到用户就校验一下用户的权限并生成登录token一起返回给前端。
扫码登录的接口都是在没有登录的时候调用的,所以要在 ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java
中把相关接口加入到允许列表中:
requests.antMatchers("/login", "/register", "/captchaImage", "/bind-openid", "/uuid/get", "/uuid/login", "/uuid/bind/openid").permitAll()
到这里我们就完成了微信扫码登录所需接口的开发,我们接着来修改页面。
1.追加接口。在ruoyi-ui/src/api/system/user.js
中追加我们上面写好的接口:
// 查询登录用uuid
export function getLoginUUid() {
return request({
url: '/uuid/get',
method: 'get'
})
}
// uuid登录
export function uuidLogin(data) {
return request({
url: '/uuid/login?uuid=' + data.uuid,
method: 'get'
})
}
2.页面修改。修改登录页ruoyi-ui/src/views/login.vue
。
2.1增加微信登录按钮及弹窗:
<div class="text-center">
<img class="mt10 wechat-icon" src="@/assets/images/wx-login.png" alt="微信登录" @click.stop="wxlogin()">
</div>
<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 v-if="bindTimeout" class="tip text-center">
二维码已失效,请点击
<i class="el-icon-refresh" @click="wxlogin"></i> 刷新
</div>
</div>
</el-dialog>
2.2导入依赖接口及相关方法:
import {
getToken
} from "@/utils/auth";
import {
getLoginUUid,
getUUid,
uuidLogin
} from "@/api/system/user";
import vueQr from 'vue-qr'
2.3引用二维码组件:
components: {
vueQr,
},
2.4data中新增属性:
timer: null,
bindWxVisible: false,
bindTimeout: false,
qrUrl: '',
2.5ruoyi-ui/src/store/modules/user.js
文件增加登录缓存方法:
// uuid登录
uuidLogin({
commit
}, userInfo) {
setToken(userInfo.token)
commit('SET_TOKEN', userInfo.token)
},
2.6登录页增加微信登录相关方法:
wxlogin() {
getLoginUUid().then(response => {
console.log(response.uuid)
const uuid = response.uuid
const redirect_uri = `http://web-hub.uat.kai12.cn/auth.html?backUrl=${本机IP}:8080/uuid/bind/openid?uuid=${uuid}`
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
let counter = 1
this.timer && clearTimeout(this.timer)
this.timer = setInterval(function() {
uuidLogin({
uuid: uuid
})
.then((res) => {
console.log(res)
counter++
console.log(counter)
if (counter === 60) {
clearTimeout(that.timer)
that.bindTimeout = true
}
if (res.status === 1) {
clearTimeout(that.timer)
that.bindWxVisible = false
that.$message({
type: 'success',
message: '登录成功',
})
clearTimeout(that.timer)
that.$store.dispatch("uuidLogin", res)
setTimeout(() => {
that.$router.push({
path: that.redirect || "/"
}).catch(() => {});
}, 1500)
}
})
.catch((err) => {
that.bindWxVisible = false
clearTimeout(that.timer)
})
}, 1000)
});
},
wxLoginClose() {
this.timer && clearTimeout(this.timer)
},
这里主要是通过轮询随机生成的uuid后,手机扫码将code以重定向的方式给到后端的 uuid/bind/openid
接口同时完成UUID传参来实现登录。
然后我们来测试一下:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。