环境条件:
- cocoscreator
- nodejs
- 认证公众号appid与appsecret
- 备案域名
流程:
- 前端拉取授权,拿到code,交给后端nodejs处理;
- 后端拿到code,换取access_token与openid;
- 换取到access_token与openid,再申请用户信息,并返回给前端;
相关链接:
1. cocoscreator拉取授权:
// <a href="https://xiaowo6.cn/t/微信登录.html" >微信登录</a>事件
onClickTest(event,customEventData){
Global.AudioManager.playSound();
//获取当前页面地址作为回调地址
let local = encodeURIComponent(window.location.origin);
let _appid = '申请到的appid'
//通过微信官方接口获取code之后,会重新刷新设置的回调地址【redirect_uri】
window.location.href = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${this._appid}&redirect_uri=${local}&response_type=code&scope=snsapi_userinfo&state=1#wechat_redirect";`
}
2. cocoscreator授权获取code:
成功授权后,微信会跳转到回调页面redirect_uri,并携带code参数,这里在onLoad中将code取出发给后端;
onLoad () {
function urlParse() {
var params = {};
if(window.location == null){
return params;
}
var name,value;
var str=window.location.href; //取得整个地址栏
var num=str.indexOf("?")
str=str.substr(num+1); //取得所有参数 stringvar.substr(start [, length ]
var arr=str.split("&"); //各个参数放到数组里
for(var i=0;i < arr.length;i++){
num=arr[i].indexOf("=");
if(num>0){
name=arr[i].substring(0,num);
value=arr[i].substr(num+1);
params[name]=value;
}
}
return params;
};
// 获取地址栏所携带code
let code = urlParse().code;
if (code){
if (code == 'false') return;
this.ui_label.string = JSON.stringify(code);
// 发送给后端
this.getaccess_token(code);
// 重新设置code,防止被刷新
window.history.replaceState(null, '','?code=false');
}
}
3. nodejs获取code:
此处新建一个nodejs项目
- 初始化项目,生成package.json文件
npm init
- 安装依赖,这里用express,虽老但好用点
npm install express
- 新建http.js文件,简单封装下后端请求微信api,放到新建utils文件夹中,代码如下:
/**
* utils/http.js
*/
var http = require('http');
var https = require('https');
var qs = require('querystring');
String.prototype.format = function(args) {
var result = this;
if (arguments.length > 0) {
if (arguments.length == 1 && typeof (args) == "object") {
for (var key in args) {
if(args[key]!=undefined){
var reg = new RegExp("({" + key + "})", "g");
result = result.replace(reg, args[key]);
}
}
}
else {
for (var i = 0; i < arguments.length; i++) {
if (arguments[i] != undefined) {
var reg = new RegExp("({)" + i + "(})", "g");
result = result.replace(reg, arguments[i]);
}
}
}
}
return result;
};
exports.post = function (host,port,path,data,callback) {
var content = qs.stringify(data);
var options = {
hostname: host,
port: port,
path: path + '?' + content,
method:'GET'
};
var req = http.request(options, function (res) {
console.log('STATUS: ' + res.statusCode);
console.log('HEADERS: ' + JSON.stringify(res.headers));
res.setEncoding('utf8');
res.on('data', function (chunk) {
callback(chunk);
});
});
req.on('error', function (e) {
console.log('problem with request: ' + e.message);
});
req.end();
};
exports.get2 = function (url,data,callback,safe) {
var content = qs.stringify(data);
var url = url + '?' + content;
var proto = http;
if(safe){
proto = https;
}
var req = proto.get(url, function (res) {
res.setEncoding('utf8');
res.on('data', function (chunk) {
var json = JSON.parse(chunk);
callback(true,json);
});
});
req.on('error', function (e) {
console.log('problem with request: ' + e.message);
callback(false,e);
});
req.end();
};
exports.get = function (host,port,path,data,callback,safe) {
var content = qs.stringify(data);
var options = {
hostname: host,
path: path + '?' + content,
method:'GET'
};
if(port){
options.port = port;
}
var proto = http;
if(safe){
proto = https;
}
var req = proto.request(options, function (res) {
res.setEncoding('utf8');
res.on('data', function (chunk) {
var json = JSON.parse(chunk);
callback(true,json);
});
});
req.on('error', function (e) {
console.log('problem with request: ' + e.message);
callback(false,e);
});
req.end();
};
exports.send = function(res,errcode,errmsg,data){
if(data == null){
data = {};
}
data.errcode = errcode;
data.errmsg = errmsg;
var jsonstr = JSON.stringify(data);
res.send(jsonstr);
};
- 新建app.js入口文件,代码如下:
var express = require('express');
var http = require("./utils/http");
var appInfo = {
appid:"wx56c35a0941285ea0",
secret:"c59f6b5541c507b467c8af5acf45252c",
};
var port = 3000;
var app = express();
app.listen(port,function(){
console.log(`监听:${host}:${port}`);
});
function send(res,ret){
var str = JSON.stringify(ret);
res.send(str)
}
//设置跨域访问
app.all('*', function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
res.header("X-Powered-By",' 3.2.1')
res.header("Content-Type", "application/json;charset=utf-8");
next();
});
app.get('/login',function(req,res){
// 前端传过来的code
var code = req.query.code;
if(code == null || code == ""){
return;
}
console.log('code is :',code);
get_access_token(code,function(suc,data){
if(suc){
var access_token = data.access_token;
var openid = data.openid;
get_state_info(access_token,openid,function(suc2,data2){
if(suc2){
// 获取到用户信息,这里发给前端
send(res,data2);
}
});
}
else{
send(res,{errcode:-1,errmsg:"unkown err."});
}
});
});
function get_access_token(code,callback){
var data = {
appid:appInfo.appid,
secret:appInfo.secret,
code:code,
grant_type:"authorization_code"
};
http.get2("https://api.weixin.qq.com/sns/oauth2/access_token",data,callback,true);
}
function get_state_info(access_token,openid,callback){
var data = {
access_token:access_token,
openid:openid
};
http.get2("https://api.weixin.qq.com/sns/userinfo",data,callback,true);
}
4. 后端开启域名访问:
宝塔面板:依赖pm2与nginx;
- 拷贝刚刚的nodejs项目至服务端;
- pm2中新建项目,启动文件选择刚刚的app.js文件,其他会自动填充;
1.png
- 映射域名,刚刚nodejs监听端口3000,这里在域名后面也得加上端口_g.xiaowo6.cn:3000_,完成后会自动新建一个静态站点(注意:服务端必须开放对应端口);
- 站点设置中,配置文件中
listen 3000; 改为 listen 80;
//server_name下面添加
location / {
proxy_pass http://127.0.0.1:3000;
}
5. 配置微信公众平台后台开发设置
JS接口安全域名:用于在该域名下调用微信开放的JS接口;
授权回调页面域名:用户在网页授权页同意授权给公众号后,微信会将授权数据传给一个回调页面,回调页面需在此域名下,以确保安全可靠;
至此,就可以用域名访问API了;