概要
现在很多企业都会和企业微信做集成绑定,通过企业微信扫码登录到内部系统,这样提高系统安全性的同时,也带来了方便,下面说说如何实现企业微信扫码登录业务。
前提
- 了解企业微信协议
- 熟悉nginx代理配置
- 熟悉vue2
- 熟悉java
整体架构流程
- 前端生成二维码,携带state,定时刷新获取登录状态
- 后端实现企业微信回调函数,绑定用户和state
- 获取到state与用户绑定关系,登录跳转
技术细节
- 前端生成二维码,携带state,定时刷新获取登录状态
这里使用vue2实现的,大家也可以用其他前端语言,上核心代码
页面显示
<template>
<div style="">
<div style="text-align: center; margin-bottom: 30px;">
<span style="font-size: 26px;">二维码登录</span>
<p style="font-size: 16px; color:#ff0000;">请使用本司的企业微信扫码</p>
</div>
<div v-show="time" style="padding-left: 35px;">
<div ref="qrCodeUrl" />
</div>
<div v-show="!time" style="text-align: center;line-height: 120px;cursor: pointer;" @click="resetQr">
二维码失效
</div>
</div>
</template>
关键函数:
生成二维码
getUrlWx() {
this.state = uuidv4() //import { v4 as uuidv4 } from 'uuid'
this.qruel = 'http://xxx/qrcode?csrfToken=' + this.state + '&portalhost=' + window.location.host//portalhost是内外网判断使用
this.createQrcode()
},
createQrcode() {
this.$refs.qrCodeUrl.innerHTML = ''
//import QRCode from 'qrcodejs2'
new QRCode(this.$refs.qrCodeUrl, {
text: this.qruel,
width: 240, // 二维码的宽度
height: 240, // 二维码的高度
colorLight: '#ffffff', // 二维码背景色
colorDark: 'black',
correctLevel: QRCode.CorrectLevel.L // 纠错等级
})
},
- 后端实现企业微信回调函数,绑定用户和state
登录企业微信后台,此时你必须有管理员权限,找到工具,通用配置,应用开发

点开通用开发参数可以看到
cropid和corpsecret,记住
我用的是旧的登录授权
例如 xxx.com xxx.com:5005,如果你没有固定的域名和ip,企业微信已升级,就会不支持
@GetMapping("/qrcode")
@ApiOperation(value = "获取企业微信登录二维码连接")
public String qrcode(HttpServletRequest request)
{
String csrfToken = request.getParameter("csrfToken");
String portalhost = request.getParameter("portalhost");//门户访问地址的主机,用于区分内外网络
String url = wxLoginService.WxLogin(csrfToken, portalhost);
return "<!DOCTYPE html>\n" +
"<html>\n" +
"<head>\n" +
"<title>企业名称</title>\n" +
"<script>window.location.href='" + url + "'</script>" +
"</html>";
}
public String WxLogin(String csrfToken, String portalhost) {
//此处通过http调用微信接口http://xxxcom:5005/cgi-bin/gettoken?corpid=xxx&corpsecret=xxx
// 同时把获取的access_token存储到redis,方便获取
//得到网页授权链接
String url = WxUtil.getCodeUrl(WxParameterConstant.redirectUri + "?portalhost=" + portalhost,false, csrfToken);
return url;
}
/**
* @description: 得到微信code,构造网页授权链接
* @author:
* @date: 2023/3/27 17:48
* @param: [redirectUri, isBecomeSilent, csrfToken]
* @return: java.lang.String
**/
//https://open.weixin.qq.com/connect/oauth2/authorize?appid=CORPID&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_base&state=STATE&agentid=AGENTID#wechat_redirect
public static String getCodeUrl(String redirectUri,boolean IsSnsapiBase,String csrfToken){
StringBuilder url = new StringBuilder("https://open.weixin.qq.com/connect/oauth2/authorize?appid=");
//企业的CorpID
url.append(WxParameterConstant.corpid);
//授权后重定向的回调链接地址,请使用urlencode对链接进行处理
//就是微信显示的页面
url.append("&redirect_uri=").append(redirectUri);
//返回类型,此时固定为:code
url.append("&response_type=code");
//应用授权作用域 snsapi_base:静默授权,可获取成员的基础信息(UserId与DeviceId); snsapi_privateinfo:手动授权,可获取成员的详细信息,包含头像、二维码等敏感信息。
if(IsSnsapiBase){
url.append("&scope=").append("snsapi_base");
}else {
url.append("&scope=").append("snsapi_privateinfo");
}
if (StringUtils.isNotEmpty(csrfToken)){
url.append("&state=").append(csrfToken);
}
// 应用agentid,建议填上该参数(如果为第三方应用或者代开发自建应用,未填该参数不会触发接口许可自动激活)。snsapi_privateinfo时必填否则报错;
url.append("&agentid=").append(WxParameterConstant.agentId);
//终端使用此参数判断是否需要带上身份信息
url.append("#wechat_redirect");
return url.toString();
}
企业微信接口文档阅读 https://developer.work.weixin.qq.com/document/path/91039
企业微信回调函数
@GetMapping ("/wxCallBack")
@ApiOperation(value = "企业微信回调链接")
public String wxCallBack(HttpServletRequest request) {
String code = request.getParameter("code");
String state = request.getParameter("state");
//redis中获取state
Object tokenJsonFirst = strOps.get(state);
JSONObject userBasics = new JSONObject();
/**
* state在Redis有对应的token信息,说明该state已经被使用过了
*/
if (tokenJsonFirst != null){
userBasics.put("errmsg", "Other users have scanned the code");
return WxResponseUtil.bad(userBasics);
}
JSONObject userResult = new JSONObject();
if (StringUtil.isNotEmpty((String) strOps.get(RedisConstant.WX_APP_ACCESS_TOKEN))){
//获取访问用户身份
//https://qyapi.weixin.qq.com/cgi-bin/auth/getuserinfo?access_token=ACCESS_TOKEN&code=CODE 获取访问用户身份
String url = WxUtil.getUserIdentityUrl((String) strOps.get(RedisConstant.WX_APP_ACCESS_TOKEN),code);
userBasics= JSONObject.parseObject(HttpClient4Util.getResponse4GetAsString(url,"utf-8"));
}else {
userBasics.put("errmsg", "wx app accesstoken is empty");
return WxResponseUtil.bad(userBasics);
}
if ("ok".equals(userBasics.getString("errmsg"))){
//获得成员信息
String urlMemBerUrl = WxUtil.getUserMemberUrl((String) strOps.get(RedisConstant.WX_APP_ACCESS_TOKEN),userBasics.getString("userid"));
userResult = JSONObject.parseObject(HttpClient4Util.getResponse4GetAsString(urlMemBerUrl,"utf-8"));
}else {
log.error("getuserinfo is not ok: " + userBasics.toJSONString());
return WxResponseUtil.bad(userBasics);
}
try
{
// 系统登录认证,此处代码省略,各位各自自己业务来处理
//主体思路是state和用户绑定,方便下一步页面请求state时知道是哪个用户
return WxResponseUtil.success();
}
catch (Exception e)
{
log.error("{}", e);
return WxResponseUtil.bad(null);
}
}
return WxResponseUtil.bad(null);
}
- 获取到state与用户绑定关系,登录跳转
定时获取登录状态
getWxToken() {
this.count = 100
this.timerState = setInterval(() => {
this.loginWx()
this.count-- // 递减
if (this.count <= 0) {
this.state = null
clearInterval(this.timerState)
}
}, 1500)
},
// 企业微信登录,Wxlogin根据自己业务来处理如何登录
async loginWx() {
this.Wxlogin(this.state).then((res) => {
if (res.code === 200) {
clearInterval(this.timerRefresh)
clearInterval(this.timerState)
this.$router.push({
path: '/'
})
}
}).catch((err) => {
console.log(err)
});
},
小结
提示:1. 熟悉企业微信通讯协议 2. 熟悉nginx反向代理 3.了解回调函数
参考链接
企业微信接口文档地址

5526

被折叠的 条评论
为什么被折叠?



