基于uniapp與node.js實(shí)現(xiàn)的微信授權(quán)登錄功能實(shí)例
前言
小程序可以通過微信官方提供的登錄能力方便地獲取微信提供的用戶身份標(biāo)識,快速建立小程序內(nèi)的用戶體系。
注意事項(xiàng)
- 會話密鑰
session_key是對用戶數(shù)據(jù)進(jìn)行 加密簽名 的密鑰。為了應(yīng)用自身的數(shù)據(jù)安全,開發(fā)者服務(wù)器不應(yīng)該把會話密鑰下發(fā)到小程序,也不應(yīng)該對外提供這個密鑰。 - 臨時登錄憑證 code 只能使用一次
授權(quán)
部分接口需要經(jīng)過用戶授權(quán)同意才能調(diào)用。我們把這些接口按使用范圍分成多個 scope ,用戶選擇對 scope 來進(jìn)行授權(quán),當(dāng)授權(quán)給一個 scope 之后,其對應(yīng)的所有接口都可以直接使用。此類接口調(diào)用時:
- 如果用戶未接受或拒絕過此權(quán)限,會彈窗詢問用戶,用戶點(diǎn)擊同意后方可調(diào)用接口;
- 如果用戶已授權(quán),可以直接調(diào)用接口;
- 如果用戶已拒絕授權(quán),則不會出現(xiàn)彈窗,而是直接進(jìn)入接口 fail 回調(diào)。請開發(fā)者兼容用戶拒絕授權(quán)的場景。
express腳手架配置
第一步:在node.js安裝完成的情況下搭建express腳手架,并在在根目錄新建config.js,內(nèi)容如下:
// token全局配置文件
module.exports = {
// 加密和解密的token秘鑰(引號中的字符可以自定義)
jwtSecretKey: 'advance8',
// token有效期
expiresIn: '8640h'
}第二步:在routes下新建router_handle/wxuser.js,并引入數(shù)據(jù)庫連接模塊以及config.js,內(nèi)容如下:
const request = require('request')
//引入連接數(shù)據(jù)庫模塊
const db = require('../conn')
//連接數(shù)據(jù)
db.connect(() => {
console.log("連接成功")
})
const jwt = require("jsonwebtoken");// 導(dǎo)入生成token的包
const config = require("../../config");
const { jwtSecretKey } = require("../../config");
exports.wxuser = (req, res) => {
let params = req.body; // 接收小程序端傳過來的所有數(shù)據(jù)
let code = params.code; //獲取小程序傳來的code
let encryptedData = params.encryptedData; //獲取小程序傳來的encryptedData
let iv = params.iv; //獲取小程序傳來的iv
let userInfo = JSON.parse(params.userInfo); //獲取個人信息
let appid = ""; //自己小程序后臺管理的appid,可登錄小程序后臺查看
let mysecret = ""; //小程序后臺管理的secret,可登錄小程序后臺查看
let grant_type = "authorization_code"; // 授權(quán)(必填)默認(rèn)值
//請求獲取openid
let url =
"https://api.weixin.qq.com/sns/jscode2session?grant_type=" +
grant_type +
"&appid=" +
appid +
"&mysecret=" +
mysecret +
"&js_code=" +
code;
request(url, (err, response, body) => {
if (!err && response.statusCode == 200) {
// 服務(wù)器返回的openid、sessionKey
let _data = JSON.parse(body);
_data.code = code;
_data.session_key = "";
// 對用戶信息進(jìn)行加密生成字符串
const wxToken = jwt.sign(_data, jwtSecretKey, {
expiresIn: config.expiresIn,
});
// 定義sql 語句,查詢當(dāng)前用戶是否存在(openid)
const sql = `select * from WeChatUser where user_id = ?`;
db.query(sql, _data.openid, (err, result) => {
if (err) return res.cc(err); //res.cc為自定義封裝,可以換成res.send
if (result.length === 0) {
const sql = `insert into WeChatUser set ?`;
db.query(
sql, {
user_id: _data.openid,
nickName: userInfo.nickName,
avatar: userInfo.avatarUrl,
gender: userInfo.gender,
},
(err, result) => {
if (err) return res.cc(err);
if (result.affectedRows !== 1) return res.cc("授權(quán)失敗,請重試");
res.send({
token: "Bearer " + wxToken,
status: 200,
messages: "WX授權(quán)成功",
});
}
);
} else {
const sql = `update WeChatUser set ? where user_id = ?`;
db.query(
sql, [{
user_id: _data.openid,
nickName: userInfo.nickName,
avatar: userInfo.avatarUrl,
gender: userInfo.gender,
},
_data.openid,
],
(err, result) => {
if (err) return res.cc(err);
res.send({
token: "Bearer " + wxToken,
status: 200,
messages: "WX授權(quán)成功",
});
}
);
}
});
} else {
res.cc("請求openid失敗");
}
});
};第三步:分別是路由模塊以及app.js的配置
var express = require('express');
var router = express.Router();
//引入連接數(shù)據(jù)庫模塊
const conn = require('./conn')
//連接數(shù)據(jù)
conn.connect(() => {
console.log("WeChatUser表連接成功")
})
var jsonWrite = function(res, ret) {
if (typeof ret === 'undefined') {
res.json({
code: '1',
msg: '操作失敗'
});
} else {
res.json(
ret
);
}
};
/*獲取微信用戶列表*/
router.post('/wxuserList', (req, res) => {
const sqlStr = `select * from WeChatUser`
conn.query(sqlStr, function(err, result) {
if (err) {
console.log(err);
}
if (result) {
jsonWrite(res, result);
}
})
});
const wxuserHandle = require('./router_handle/wxuser')
router.post('/wxuser', wxuserHandle.wxuser)
module.exports = router;var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'code/public')));
// error handler
app.use(function(err, req, res, next) {
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
res.status(err.status || 500);
res.render('error');
});
const wxuserApi = require('./routes/index');
// 允許跨域
app.all('*', function(req, res, next) {
console.log(req.headers.origin)
console.log(req.environ)
// res.header("Access-Control-Allow-Origin", req.headers.origin);
//設(shè)置允許跨域的域名,*代表允許任意域名跨域
res.header("Access-Control-Allow-Origin", "*");
//允許的header類型
res.header("Access-Control-Allow-Headers", "content-type");
//跨域允許的請求方式
res.header("Access-Control-Allow-Methods", "DELETE,PUT,POST,GET,OPTIONS");
if (req.method == 'OPTIONS') {
/*讓options請求快速返回*/
res.sendStatus(200)
} else {
next()
}
});
app.use('/wxuser', wxuserApi);
//配置默認(rèn)端口
app.listen(3008, () => {
console.log("服務(wù)器已啟動")
})
module.exports = app;最后,啟動服務(wù)器,顯示如下內(nèi)容表示成功

uniapp配置
HTML
<button class="cu-btn block bg-green margin-tb-sm lg shadow" @click="getUserProfile">
微信一鍵登錄
</button>JS
methods(){
getUserProfile: function(e) {
var that=this;
// 獲取個人信息
wx.getUserProfile({
desc: '用于獲取用戶個人信息',
success: function(detail) {
wx.login({
success(res) {
var code = res.code; //登錄憑證
uni.request({
url: '',
// 需要傳給后端的數(shù)據(jù)
data: {
encryptedData: detail.encryptedData,
iv: detail.iv,
code: code,
userInfo: detail.rawData
},
method: 'post',
success: function(res) {
// 將用戶授權(quán)信息存儲到本地
wx.setStorageSync('userinfo', detail.userInfo)
// 將后端返回的token存儲到本地
wx.setStorageSync('token', res.data.token)
//通過接口獲取數(shù)據(jù)庫中數(shù)據(jù)
uni.request({
url:'',
data: {},
method: 'post',
header: {
'content-type': 'application/json'
},
success: (res) => {
that.nickName=res.data[0].nickName
that.avatar=res.data[0].avatar
}
})
},
fail: function() {
console.log('系統(tǒng)錯誤')
}
})
}
});
},
fail: function() {
wx.showModal({
content: '取消授權(quán)將會影響相關(guān)服務(wù),您確定取消授權(quán)嗎?',
success(res) {
if (res.confirm) {
wx.showToast({
title: '已取消授權(quán)',
duration: 1500
})
} else if (res.cancel) {
this.getUserProfile()
}
}
})
}
})
}
}運(yùn)行結(jié)果



總結(jié)
到此這篇關(guān)于基于uniapp與node.js實(shí)現(xiàn)的微信授權(quán)登錄功能的文章就介紹到這了,更多相關(guān)uniapp與node.js微信授權(quán)登錄內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
node 利用進(jìn)程通信實(shí)現(xiàn)Cluster共享內(nèi)存
本篇文章主要介紹了node 利用進(jìn)程通信實(shí)現(xiàn)Cluster共享內(nèi)存,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-10-10
node管理統(tǒng)計(jì)文件大小并顯示目錄磁盤空間狀態(tài)從零實(shí)現(xiàn)
這篇文章主要為大家介紹了node管理統(tǒng)計(jì)文件大小并顯示目錄磁盤空間狀態(tài)的從零實(shí)現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12
PHP和NodeJs開發(fā)的應(yīng)用如何共用Session
這篇文章主要介紹了PHP和NodeJs開發(fā)的應(yīng)用如何共用Session的相關(guān)資料及思路,需要的朋友可以參考下2015-04-04
深入學(xué)習(xí)nodejs中的async模塊的使用方法
本篇文章主要介紹了nodejs中的async模塊的使用方法,具有一定的參考價值,有興趣的可以了解一下2017-07-07
Node交互式的SFTP上傳實(shí)現(xiàn)過程剖析
這篇文章主要為大家介紹了Node交互式的SFTP上傳實(shí)現(xiàn)過程剖析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08
Node.js上傳文件功能之服務(wù)端如何獲取文件上傳進(jìn)度
這篇文章主要介紹如何利用progress-stream獲取文件上傳進(jìn)度,以及該組件使用過程中的注意事項(xiàng)2018-02-02
xtemplate node.js 的使用方法實(shí)例解析
這篇文章主要介紹了xtemplate node.js 的使用方法實(shí)例說明,非常不錯,介紹的非常詳細(xì),具有參考借鑒價值,需要的朋友可以參考下2016-08-08

