TNW: TypeScript(The) + Node.js(Next) + WeChat 微信公衆號開發腳手架,支持任何 Node.js 的服務端框架(Express、Nest、egg 等)vue
請參考以前寫的文章 微信公衆號開發之受權獲取用戶信息-Java版 此篇文章已有 2.4 w+ 的閱讀量git
關於網頁受權的兩種scope的區別說明typescript
一、以 snsapi_base 爲 scope 發起的網頁受權,是用來獲取進入頁面的用戶的 openid 的,而且是靜默受權並自動跳轉到回調頁的。用戶感知的就是直接進入了回調頁(每每是業務頁面)api
二、以 snsapi_userinfo 爲 scope 發起的網頁受權,是用來獲取用戶的基本信息的。但這種受權須要用戶手動贊成,而且因爲用戶贊成過,因此無須關注,就可在受權後獲取該用戶的基本信息。安全
三、用戶管理
類接口中的 獲取用戶基本信息接口
,是在用戶和公衆號產生消息交互或關注後事件推送後,才能根據用戶 openid 來獲取用戶基本信息。這個接口,包括其餘微信接口,都是須要該用戶(即openid)關注了公衆號後,才能調用成功的。微信
關於特殊場景下的靜默受權微信開發
一、上面已經提到,對於以snsapi_base爲scope的網頁受權,就靜默受權的,用戶無感知;架構
二、對於已關注公衆號的用戶,若是用戶從公衆號的會話或者自定義菜單進入本公衆號的網頁受權頁,即便是scope爲snsapi_userinfo,也是靜默受權,用戶無感知。app
具體而言,網頁受權流程分爲四步:微信公衆平臺
一、引導用戶進入受權頁面贊成受權,獲取code
二、經過 code 換取網頁受權 access_token(與基礎支持中的access_token不一樣)
三、若是須要,開發者能夠刷新網頁受權 access_token,避免過時
四、經過網頁受權 access_token 和 openid 獲取用戶基本信息(支持UnionID機制)
引導關注者打開以下受權的頁面URL:
open.weixin.qq.com/connect/oau…
若提示「該連接沒法訪問」,請檢查參數是否填寫錯誤,是否擁有scope參數對應的受權做用域權限。
尤爲注意:
若是用戶贊成受權,頁面將跳轉至 redirect_uri/?code=CODE&state=STATE。
特別注意 : code做爲換取 access_token 的票據,每次用戶受權帶上的 code 將不同,code 只能使用一次,5分鐘未被使用自動過時。
經過code換取網頁受權access_token
刷新access_token(若是須要)
拉取用戶信息(需scope爲 snsapi_userinfo)
檢驗受權憑證(access_token)是否有效
export class SnsAccessTokenApi {
private static authorizeUrl: string = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=%s";
private static accessTokenUrl: string = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code"
private static refreshTokenUrl: string = "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=%s&grant_type=refresh_token&refresh_token=%s"
private static userInfoUrl: string = "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=%s";
private static checkTokenUrl: string = "https://api.weixin.qq.com/sns/auth?access_token=%s&openid=%s";
/** * 獲取受權連接 * @param redirectUri 回調地址 * @param scope * @param state */
public static getAuthorizeUrl(redirectUri: string, scope: ScopeEnum, state?: string): string {
let url = util.format(this.authorizeUrl, ApiConfigKit.getApiConfig.getAppId, urlencode(redirectUri), scope);
if (state) {
url = url + "&state=" + state;
}
return url + "#wechat_redirect";
}
/** * 經過code換取網頁受權access_token * @param code */
public static async getSnsAccessToken(code: string) {
let url = util.format(this.accessTokenUrl, ApiConfigKit.getApiConfig.getAppId,
ApiConfigKit.getApiConfig.getAppScrect, code);
return HttpKit.getHttpDelegate.httpGet(url);
}
/** * 刷新access_token * @param refreshToken */
public static async refreshAccessToken(refreshToken: string) {
let url = util.format(this.refreshTokenUrl, ApiConfigKit.getApiConfig.getAppId, refreshToken);
return HttpKit.getHttpDelegate.httpGet(url);
}
/** * 檢驗受權憑證(access_token)是否有效 * @param accessToken 經過code換取的access_token * @param openId */
public static async checkAccessToken(accessToken: string, openId: string) {
let url = util.format(this.checkTokenUrl, accessToken, openId);
return HttpKit.getHttpDelegate.httpGet(url);
}
/** * 拉取用戶信息(需scope爲 snsapi_userinfo) * @param accessToken * @param openId * @param lang */
public static async getUserInfo(accessToken: string, openId: string, lang: Lang) {
let url = util.format(this.userInfoUrl, accessToken, openId, lang);
return HttpKit.getHttpDelegate.httpGet(url);
}
}
export enum ScopeEnum {
SNSAPI_BASE = "snsapi_base",
SNSAPI_USERINFO = "snsapi_userinfo"
}
export enum Lang {
ZH_CN = "zh_CN",
ZH_TW = "zh_TW",
EN = "en"
}
複製代碼
訪問:http/https://域名/toAuth
回調:http/https://域名/auth
app.get('/toAuth', (req, res) => {
let url = SnsAccessTokenApi.getAuthorizeUrl("http://xxx/auth", ScopeEnum.SNSAPI_USERINFO, "IJPay");
console.log("受權URL:", url);
res.redirect(url);
});
// 受權回調
app.get('/auth', (req, res) => {
let code = req.query.code;
let state = req.query.state;
console.log("code:", code, " state:", state);
SnsAccessTokenApi.getSnsAccessToken(code).then(data => {
let temp = JSON.parse(data.toString());
// 判斷 access_token 是否獲取成功
if (temp.errcode) {
// access_token 獲取失敗
res.send(temp);
return;
}
let access_token = temp.access_token;
let openid = temp.openid;
let scope = temp.scope;
if (scope == ScopeEnum.SNSAPI_USERINFO) {
// 獲取用戶信息
SnsAccessTokenApi.getUserInfo(access_token, openid, Lang.ZH_CN).then(data => {
res.send(data);
});
} else {
res.send(temp);
}
})
});
複製代碼
一、請在微信客戶端中打開
受權獲取用戶信息必須在微信客戶端中打開或者使用微信提供的 微信開發者工具
二、redirect_url 參數錯誤
請檢查appId對應的公衆平臺中設置的受權域名是否與你項目中配置的域名保持一致
三、測試號測試時提示未關注測試號
測試號測試受權是必須先關注的測試的號,官方這作是爲了安全。正式環境微信認證的服務號是不用關注就能夠獲取用戶的信息。
TNW
微信公衆號開發腳手架:gitee.com/javen205/TN…IJPay
讓支付觸手可及:gitee.com/javen205/IJ…mica
工具集:gitee.com/596392912/m…Avue
一款基於 vue 可配置化的神奇框架:gitee.com/smallweigit…pig
宇宙最強微服務(架構師必備):gitee.com/log4j/pigSpringBlade
完整的線上解決方案(企業開發必備):gitee.com/smallc/Spri…