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…