@truenewx/tnxcore
Version:
互联网技术解决方案:JavaScript核心扩展支持
174 lines (160 loc) • 6.72 kB
text/typescript
/**
* 微信登录客户端支持
*/
import {base64} from '../util/string.ts';
type WxLoginOptions = {
id: string;
appid: string;
scope: string;
redirect_uri: string;
state: any;
styletype?: string;
sizetype?: string;
bgcolor?: string;
rst?: string;
style?: string;
href?: string;
lang?: 'en' | string;
stylelite?: number;
fast_login?: number;
color_scheme?: 'auto' | 'dark' | 'light';
onReady?: (ready: boolean) => void;
onQRcodeReady?: () => void;
onCleanup?: () => void;
self_redirect?: boolean;
};
(function (e: Window, t: Document) {
(e as any).WxLogin = function (o: WxLoginOptions) {
let n = "default";
if (o.self_redirect === true) {
n = "true";
} else if (o.self_redirect === false) {
n = "false";
}
const r = t.createElement("iframe") as HTMLIFrameElement;
const s = (new Date).getTime();
let a = "https://open.weixin.qq.com/connect/qrconnect?appid=" + o.appid + "&scope=" + o.scope + "&redirect_uri=" + o.redirect_uri + "&state=" + o.state + "&login_type=jssdk&self_redirect=" + n + "&styletype=" + (o.styletype || "") + "&sizetype=" + (o.sizetype || "") + "&bgcolor=" + (o.bgcolor || "") + "&rst=" + (o.rst || "") + "&ts=" + s;
a += o.style ? "&style=" + o.style : "";
a += o.href ? "&href=" + o.href : "";
a += o.lang === "en" ? "&lang=en" : "";
a += o.stylelite === 1 ? "&stylelite=1" : "";
a += o.fast_login === 0 ? "&fast_login=0" : "";
if (o.color_scheme === "auto") {
a += "&color_scheme=auto";
} else if (o.color_scheme === "dark") {
a += "&color_scheme=dark";
} else if (o.color_scheme === "light") {
a += "&color_scheme=light";
}
r.src = a;
r.setAttribute("frameBorder", "0");
r.setAttribute("allowTransparency", "true");
r.setAttribute("scrolling", "no");
r.style.width = "300px";
r.style.height = "400px";
r.allow = "local-network-access";
const c = t.getElementById(o.id);
if (c && e.addEventListener && (e as any).JSON) {
c.innerHTML = "";
c.appendChild(r);
const i = function (evt: MessageEvent) {
if (evt.origin === "https://open.weixin.qq.com") {
try {
const n = JSON.parse((evt as any).data);
if (n && n.type === "status") {
const ready = n.status === "wxReady";
if (ready && o.onReady && typeof o.onReady === "function") {
o.onReady(ready);
}
if (n.status === "wxQRcodeReady" && o.onQRcodeReady && typeof o.onQRcodeReady === "function") {
o.onQRcodeReady();
}
}
} catch (err) {
if (console && typeof console.log === "function") {
console.log("wxLogin postMessage error", err);
}
}
}
};
e.addEventListener("message", i, false);
let l = false;
o.onCleanup = function () {
if (!l && e.removeEventListener) {
e.removeEventListener("message", i, false);
l = true;
}
}
}
}
})(window, document);
// 以上代码改编自 http://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js
function standardizeRedirectUri(redirectUri: string, productContextUri: string): string {
let protocol = window.location.protocol;
let host = window.location.host;
let uri = protocol + '//' + productContextUri;
if (productContextUri.startsWith(host)) {
uri += redirectUri;
} else { // 不是生产环境则借助于生产环境的直接重定向能力进行再跳转
uri += '/redirect/';
if (redirectUri.startsWith('/')) { // 目标跳转地址是相对地址,则加上当前网站根地址
uri += protocol.substring(0, protocol.length - 1) + '/' + host + redirectUri;
} else { // 不以/开头,视为绝对地址
let index = redirectUri.indexOf('://');
if (index < 0) { // 绝对地址中一定包含://
console.error('错误的跳转目标地址:' + redirectUri);
return;
}
uri += redirectUri.substring(0, index); // 协议部分
uri += redirectUri.substring(index + 2);
}
}
return encodeURI(uri);
}
function standardizeState(state) {
let stateString = '';
if (typeof state === 'object') {
stateString = JSON.stringify(state);
stateString = base64.encode(stateString);
if (stateString.length > 128) {
delete state._next;
stateString = JSON.stringify(state);
stateString = base64.encode(stateString);
}
}
return stateString;
}
export default class Wechat {
appId = '';
productContextUri = '';
constructor(appId, productContextUri) {
this.appId = appId;
this.productContextUri = productContextUri;
}
login(containerId, redirectUri, options) {
options = options || {};
if (options.cssHref && options.cssHref.startsWith('/')) {
options.cssHref = window.location.protocol + '//' + window.location.host + options.cssHref;
}
new window.WxLogin({
id: containerId,
appid: this.appId,
scope: "snsapi_login",
redirect_uri: standardizeRedirectUri(redirectUri, this.productContextUri),
href: options.cssHref,
state: standardizeState(options.state),
});
}
authorize(redirectUri, state, silent) {
// 请求参数有严格的顺序要求,不能更改参数顺序
let url = window.location.protocol + '//open.weixin.qq.com/connect/oauth2/authorize?appid=' + this.appId;
url += '&redirect_uri=' + standardizeRedirectUri(redirectUri, this.productContextUri);
url += '&response_type=code';
url += '&scope=' + (silent ? 'snsapi_base' : 'snsapi_userinfo');
state = standardizeState(state);
if (state) {
url += '&state=' + state;
}
window.location.href = url;
}
}