1.背景
最近プロジェクトを受け取ったが、元のプロジェクトチーム(製品、技術)が解散し、引き継ぎの状況は不明で、誰も引き継がなかった。たまたま、私が担当していた事業がこれらのプロジェクトと半額の関係にあったのですが、他のチームが私を見つけたときも、3つの質問をして混乱し、ソースコードがありませんでした。そこで、部門マネージャーに支援を依頼し(gitlabの許可、会社全体のプロジェクトを探す)、プロジェクトのソースコードを見つけた後、バックエンドはPHPですが、関係者にリファクタリングが必要であることを伝えました。私は自分で関連ページとPHPソースコードを調べ、どのビジネスが関係しているかを理解し、3、2日間熟考し、ついにその理由を知りました。。。
2、開発のアイデア
1.以下のスクリーンショットに示すように、エンタープライズWeChatアプリケーションを構成し、エンタープライズWeChatバックエンドに移動して構成を管理します。
2.ページアドレス。展開後のドメイン名アクセスがhttps://www.aaa.com/wp_wework/workphoto/homeの 場合、この信頼できるドメイン名を構成し、カスタムアプリケーションを見つけて、次のように構成する必要があります。 :
3.ページ認証、ユーザーはエンタープライズWeChatを使用してエンタープライズWeChatのアプリケーションページを操作でき、ページはユーザー情報を取得できます。では、それらの間の承認関係は何ですか?これが重要なポイントです。
1)会社のjsapi_ticketを取得します。関連する操作は次のとおりです。
A.関連するパラメーター:dtoフィールド
{{
private String corpId; // 企业微信ID
private String agentId; // 应用ID
private String url; // 可信赖域名
}
public String getCorpTicket(String corpId, String agentId , QyAgentCommondUrlDTO dto) {
// 获取 redis 的缓存数据
String res = repository.get(QYWEIXIN_JSAPI_TICKET_KEY+dto.getCorpId()+dto.getAgentId());
String jsapi_ticket = "";
if(StringUtil.isEmpty(res)){
// 调用 企业微信的接口:获取企业的jsapi_ticket
String result = OAuthApi.getJsapiTicket().getJson();
JSONObject resultJson = JSONObject.parseObject(result);
if(resultJson.get("ticket") != null){
jsapi_ticket = resultJson.getString("ticket");
repository.setExpire(QYWEIXIN_JSAPI_TICKET_KEY+dto.getCorpId()+dto.getAgentId(),result,7200);
}
}else{
JSONObject resJson = JSONObject.parseObject(res);
jsapi_ticket = resJson.getString("ticket");
}
//生成的随机字符串
String nonce_str = StringUtilsX.getRandomStringByLength(32);
//时间戳
Long timeStamp = System.currentTimeMillis() / 1000;
String stringSignTemp = "jsapi_ticket="+jsapi_ticket+"&noncestr=" + nonce_str+"×tamp=" + timeStamp
+"&url="+dto.getUrl();
String signature = StringUtilsX.getSha1(stringSignTemp);
net.sf.json.JSONObject tickJson = new net.sf.json.JSONObject();
tickJson.put("appId",dto.getCorpId());
tickJson.put("timestamp",timeStamp);
tickJson.put("nonceStr",nonce_str);
tickJson.put("signature",signature);
tickJson.put("isSuccess",Boolean.TRUE);
tickJson.put("responseCode",0);
tickJson.put("responseMsg","请求成功");
logger.info("---getJsticket--results:"+tickJson);
return tickJson.toString();
}
// 加解密类
public class StringUtilsX {
/**
* StringUtils工具类方法 获取一定长度的随机字符串,范围0-9,a-z
*
* @return 一定长度的随机字符串
*/
public static String getRandomStringByLength(int length) {
String base = "abcdefghijklmnopqrstuvwxyz0123456789";
Random random = new Random();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < length; i++) {
int number = random.nextInt(base.length());
sb.append(base.charAt(number));
}
return sb.toString();
}
/**
* sha1 加密
* @param str
* @return
*/
public static String getSha1(String str){
if(str==null||str.length()==0){
return null;
}
char hexDigits[] = {'0','1','2','3','4','5','6','7','8','9',
'a','b','c','d','e','f'};
try {
MessageDigest mdTemp = MessageDigest.getInstance("SHA1");
mdTemp.update(str.getBytes("UTF-8"));
byte[] md = mdTemp.digest();
int j = md.length;
char buf[] = new char[j*2];
int k = 0;
for (int i = 0; i < j; i++) {
byte byte0 = md[i];
buf[k++] = hexDigits[byte0 >>> 4 & 0xf];
buf[k++] = hexDigits[byte0 & 0xf];
}
return new String(buf);
} catch (Exception e) {
// TODO: handle exception
return null;
}
}
}
Js処理フロントエンドインターフェース:これは主に、インターフェースを承認するために買収された会社jsapi_ticket およびjsapi_ticket買収アプリケーションです。注:wxCorpConfig、wxAgentConfigは現在wxCorpConfigを使用していますが、wxAgentConfigは一時的に使用できません。
async function wxShareRequest({ url, title, desc, link, imgUrl, phone } = {}) {
try {
// 开发环境
let domain = process.env.NODE_ENV == 'development' ? 'https://www.aaa.com/wp_wework/' : 'https://www.bbbb.com/wp_wework/';
let wxCorpConfig = await getWxplatformCorpConfig()
let wxAgentConfig = await getWxplatformAgentConfig()
if (wxCorpConfig === false || wxAgentConfig === false) return
wx.config({
beta: true,// 必须这么写,否则wx.invoke调用形式的jsapi会有问题
debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: wxCorpConfig.appId, // 必填,企业微信的corpID
timestamp: wxCorpConfig.timestamp, // 必填,生成签名的时间戳
nonceStr: wxCorpConfig.nonceStr, // 必填,生成签名的随机串
signature: wxCorpConfig.signature, // 必填,签名,见 附录-JS-SDK使用权限签名算法
jsApiList: ['openUserProfile','agentConfig', 'onMenuShareAppMessage', 'onMenuShareWechat', 'onMenuShareTimeline'] // 必填,需要使用的JS接口列表,凡是要调用的接口都需要传进来
});
wx.ready(function() {
wx.onMenuShareAppMessage({
title: '工作形象照', // 分享标题
desc: '蓝月亮的小伙伴,快来制作你的专属企业微信头像吧!', //'快速制作企业微信头像 ', // 分享描述
link: domain, // 分享链接;在微信上分享时,该链接的域名必须与企业某个应用的可信域名一致
imgUrl: domain + (imgUrl || '/static/img/share.png'), // 分享图标
success: function() {
// 用户确认分享后执行的回调函数
},
cancel: function() {
// 用户取消分享后执行的回调函数
}
});
wx.onMenuShareWechat({
title: '工作形象照', // 分享标题
desc: '蓝月亮的小伙伴,快来制作你的专属企业微信头像吧!', // 分享描述
link: domain, // 分享链接
imgUrl: domain + (imgUrl || '/static/img/share.png'), // 分享图标
success: function() {
// 用户确认分享后执行的回调函数
},
cancel: function() {
// 用户取消分享后执行的回调函数
}
});
wx.onMenuShareTimeline({
title: '工作形象照', // 分享标题
link: domain, // 分享链接
imgUrl: domain + (imgUrl || '/static/img/share.png'), // 分享图标
success: function() {
// 用户确认分享后执行的回调函数
},
cancel: function() {
// 用户取消分享后执行的回调函数
}
});
});
} catch (error) {
}
}
2)Webページ認証方法、Webページ認証ログイン、これは主にユーザー情報を取得するためのもので、ログイン後、次の図に示すようにトークンがあります。
ここには2つのステップがあります。
最初のステップ:アプリケーションをクリックすると、ページがジャンプします。ページの初期プロセスでは、ジャンプ権限を構成する必要があります。ここでは、次のように、ルーティングジャンプ設定に焦点を当てています。
数量:获取コード 、既是:window.location.href = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid =' + global.AppId + '&redirect_uri =' + encodeURIComponent(global.domain + to.fullPath)+ '&response_type = code&scope = snsapi_base&agentid =' + global.agentId + '&state = STATE#wechat_redirect'
// 白名单
const whiteList = ['/login', '/register'] // no redirect whitelist
const agent = window.navigator.userAgent.toLowerCase();
// 全局路由卫士
router.beforeEach((to, from, next) => {
// 设置页面title
document.title = getPageTitle(to.meta.title);
// 确定用户是否已登录(cookie中是否有token) getToken();
const hasToken = getToken();
if (hasToken) {
next()
} else {
console.log(to)
/* has no token*/
// 在免登录白名单,直接进入
if (whiteList.indexOf(to.path) !== -1) {
next()
} else {
// 没有访问权限的其他页面被重定向到登录页面。
// redirect 后携带登录后要访问的页面 to.fullPath 可将query中的参数一并带入
// next(`/login?redirect=${encodeURIComponent(to.fullPath)}`);
/**
* 微信授权
* @description 微信环境则走微信授权获取个人信息及支持微信支付
*/
// 判断是否为微信环境 utils.isWechat
if (agent.match(/MicroMessenger/i) == "micromessenger") {
// 判断是否微信授权过
// 判断是否有微信授权回调 code
if (!to.query.code) {
window.location.href = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid=' + global.AppId + '&redirect_uri=' + encodeURIComponent(global.domain + to.fullPath) + '&response_type=code&scope=snsapi_base&agentid='+global.agentId+'&state=STATE#wechat_redirect'
} else {
let corpId = global.AppId; // 企业微信ID
let agentId = global.agentId; // 应用ID
let param ={
corpId: corpId,
agentId: agentId,
code: to.query.code.trim()
}
// 通过code获取用户信息
authAction(param).then(response => {
if (response.data.success) {
let obj = response.data.data;
if (!obj){
console.log("后台返回为空的用户对象");
return ;
}
let item = {
name: obj.name,
employeeNo:obj.userid,
gender:obj.gender,
corpId: corpId,
agentId: agentId
}
let token = obj.userid;
setToken(token);
setUserInfo(item);
}
next('/');
}).catch(error => {
console.error(error)
})
}
} else {
Toast({
message: '请在企业微信客户端打开',
forbidClick: true, // 禁用背景点击
duration: 2000
});
}
}
}
})
ステップ2:ユーザー情報を取得する方法は次のとおり です。authAction。ここでの背景では、コードに従ってメンバー情報を取得する方法 とメンバーを 読み取る方法の2つの方法を呼び出します 。前者はエンタープライズWeChat従業員番号を取得し、後者は従業員番号に従ってユーザー情報を取得します。 。この時点で、ページ全体が正常に承認されます。フロントエンドは、ユーザー情報をキャッシュするのに適しています。
3、まとめ
1.エンタープライズWeChatでアプリケーションをクリックした後の認証の問題(企業のjsapi_ticket、Webページ認証ログインの取得)、ページジャンプに焦点を当てるのは、ルートジャンププロセスの認証です。
2.エンタープライズWeChatインターフェイス呼び出しの承認処理には、エンタープライズWeChatアプリケーションの構成情報が必要です。
3.フロントエンドページは、ユーザーが承認された後にユーザー情報をキャッシュします。Cookieをお勧めします。
4.この記事は比較的大まかなもので、エンタープライズWeChatカスタムアプリケーションのページ認証のアイデアを簡単に説明することを目的としています。簡単に言えば、どのページが許可されているか、既存の許可インターフェースは何か、渡されるパラメーターは何か、そして何に注意を払うべきか。