需求背景
公司的内部基建应用众多,为便于全司员工内部的使用方便,所以单独将登录系统抽出来作为一个单独的应用,统一基建平台下的所有应用的登录风格,一个应用登录成功之后,这个登录系统下属的所有应用全部默认登录成功。这个方式叫做SSO登录。 SSO登录介绍:
部分应用未接入这个登录系统之前,拥有自己的登录方式,包含企微的扫码登录,现在为了兼容所有应用,以及用户能够方便使用登录系统,在原有基础之上增加企微扫码登录功能。
企微扫码授权登录官方文档
实现方案
企微登录流程图
这个流程图就是整个登录行为的全过程,前端所需要做的就是构造登录链接->跳转登录链接/嵌入登录链接到页面里->展示登录链接->用户扫码点击登录->后端鉴权控制跳转至重定向页面或者登录失败页面
步骤:
1.开启网页授权登录:登录 企业管理端后台->进入需要开启的自建应用->点击 “企业微信授权登录”,进入如下页面
然后点击 "设置授权回调域",输入回调域名,点击“保存”。
要求配置的授权回调域,必须与访问链接的域名完全一致。举个例子:
- 假定重定向访问的链接是:mail.qq.com:8080/cgi-bin/log…
| 配置域名 | 是否正确 | 原因 |
|---|---|---|
| mail.qq.com:8080 | 配置域名与访问域名完全一致 | |
| email.qq.com | 配置域名必须与访问域名完全一致 | |
| support.mail.qq.com | 配置域名必须与访问域名完全一致 | |
| *.qq.com | 不支持泛域名设置 | |
| mail.qq.com | 配置域名必须与访问域名完全一致,包括端口号 | |
| mail.qq.com:8080 | 不包括协议头 |
第一步:实现二维码登录样式
在原本账号密码登录的界面基础上,加上二维码的交互,值得一提的是,右上角的样式实现,放一个正方形盒子放二维码图标,然后再用border的那一套画出一个三角形盖住,就有了这种效果。这里的样式借鉴了其他网站,稍微做了放大缩小的效果。其次,鼠标放上去之后颜色变化,这个图标是直接从iconfont网站上找的,你下载下来之后使用会发现不变色,原因是iconfont上的图标默认是带了颜色的,svg标签的属性上面有个fill属性是规定颜色的,可以在iconfont中统一去除再用,就可以跟字体一样设置颜色了。
第二步:给二维码图标那边的盒子增加点击事件,切换到二维码容器界面
容器样式代码:
<div>
<div className="wx-login">
{qrcodeVisible && (
<div className="wx-box">
<Select
defaultValue={currentCompany.companyIdDisplayName || undefined}
style={{ width: 200 }}
onChange={(value) => {
const newCompany = JSON.parse(value);
localStorage.setItem(
'SSO_USER_COMPANY',
JSON.stringify(newCompany.companyId)
);
initQrcode(newCompany);
}}
>
{companyList.length > 0
&& companyList.map((item) => {
return (
<Option key={item.cropId} value={JSON.stringify(item)}>
{item.companyIdDisplayName}
</Option>
);
})}
</Select>
</div>
)}
<div id="wx_reg" className={qrcodeVisible ? '' : 'hidden'} />
</div>
{isShowQrcode && (
<div className="toggle-icon" onClick={toggleLogin}>
{qrcodeVisible ? (
<i className="iconfont icon-diannao" />
) : (
<i className="iconfont icon-erweima" />
)}
<div className="cover" />
</div>
)}
</div>
第三步:在切换到二维码登录界面的同时,调用企微的sdk,实例化一个二维码容器
引入企微sdk
可以直接在打包出口的html文件的Link中直接引入
或者:
点击事件之后实例化二维码容器
这里有个坑,引入sdk之后,vue跟react中,api挂载的地方不一样- vue可以直接使用,react中是挂载在window上面的
- 这个实例化的对象id是放置企微二维码的盒子容器id
- 如果是单个应用的登录系统,appid跟agentid是公司跟企微服务台那边申请的固定的id,我这里是要支持不同公司的不同应用,所以上面做了一个下拉框用于选择公司,下拉框里有不同公司,不同公司的数据里包含了appid,agentid,每次切换重新init实例化,就可以生成新的二维码
- 根据sso登录原理,从子应用跳转到这个页面的时候,url中带着应用地址以及target,在此基础上向后端发请求,后端可以识别当前应用,然后返回对应的公司列表,包含appid,以及agentid。
- 重定向地址为后端约定,本项目是拼接子应用的地址加/verifyWechatCode
- state中存放后端需要的参数,用于鉴权+跳转,这里的参数需要进行base64转码
- 这个二维码生成,扫码之后会生成一个base64转码的链接
/**
* @description: react初始化二维码
* @param {*} company
* @return {*}
*/
const initQrcode = (company) => {
const obj = new window.WwLogin({
id: 'wx_reg', // 登录页面显示二维码的容器id
appid: company.cropId, // 企业微信的CorpID,在企业微信管理端查看
agentid: company.wechatAppId, // 授权方的网页应用id,在具体的网页应用中查看
redirect_uri: `${window.location.protocol}//${window.location.host}/verifyWechatCode`, // 重定向地址
state: window.btoa(
JSON.stringify({
companyId: company.companyId,
service,
target,
cropId: company.cropId,
callbackDomain: window.location.host,
wechatAppId: company.wechatAppId,
})
), // 额外向后端传的值
lang: 'zh',
});
};
/**
* @description: vue初始化二维码
* @param {*} company
* @return {*}
*/
const initQrcode = (company) => {
const obj = new WwLogin({
id: 'wx_reg', // 登录页面显示二维码的容器id
appid: company.cropId, // 企业微信的CorpID,在企业微信管理端查看
agentid: company.wechatAppId, // 授权方的网页应用id,在具体的网页应用中查看
redirect_uri: `${window.location.protocol}//${window.location.host}/verifyWechatCode`, // 重定向地址
state: window.btoa(
JSON.stringify({
companyId: company.companyId,
service,
target,
cropId: company.cropId,
callbackDomain: window.location.host,
wechatAppId: company.wechatAppId,
})
), // 额外向后端传的值
lang: 'zh',
});
};
第四步:扫码成功之后,在企微端确认登录,生成链接跳转,后端在此过程中鉴权并决定是否跳转对应子应用,成功或失败
sso机制下的登录系统,大多是由后端进行鉴权以及跳转,前端的事很少