提交 e26e86ac 编写于 作者: DCloud_JSON's avatar DCloud_JSON

- 保存到改用异步方法,方便通过拦截器执行更新后的操作 - 新增通过拦截器监听更新,调用云函数刷新刷新设备信息token有效期的API - 删除留言板示例 - 修复图片验证码样式问题

上级 c26635f7
...@@ -163,7 +163,6 @@ uni-starter服务端使用[uni-config-center](https://ext.dcloud.net.cn/plugin?i ...@@ -163,7 +163,6 @@ uni-starter服务端使用[uni-config-center](https://ext.dcloud.net.cn/plugin?i
"/pages/common/webview/webview", "/pages/common/webview/webview",
"/pages/grid/grid", "/pages/grid/grid",
"/pages/ucenter/ucenter", "/pages/ucenter/ucenter",
"/pages/ucenter/guestbook/guestbook",
"/pages/ucenter/about/about", "/pages/ucenter/about/about",
"/pages/ucenter/settings/settings" "/pages/ucenter/settings/settings"
] ]
......
## 1.1.29(2022-01-25)
- 保存`uni_id_token``storage`改用异步方法,方便通过拦截器执行`token`更新后的操作
- 新增通过拦截器监听`uni_id_token`更新,调用云函数刷新刷新设备信息token有效期的API `renewDeviceTokenExpired`
- 删除留言板示例
- 修复图片验证码样式问题
## 1.1.28(2022-01-12) ## 1.1.28(2022-01-12)
删除list页第37行多了个`?`引起的报错 删除list页第37行多了个`?`引起的报错
## 1.1.27(2022-01-11) ## 1.1.27(2022-01-11)
......
...@@ -88,8 +88,7 @@ export default async function() { ...@@ -88,8 +88,7 @@ export default async function() {
'TOKEN_INVALID', 'TOKEN_INVALID',
'TOKEN_INVALID_TOKEN_EXPIRED', 'TOKEN_INVALID_TOKEN_EXPIRED',
'TOKEN_INVALID_WRONG_TOKEN', 'TOKEN_INVALID_WRONG_TOKEN',
'TOKEN_INVALID_ANONYMOUS_USER', 'TOKEN_INVALID_ANONYMOUS_USER'
].includes(code)) { ].includes(code)) {
uni.navigateTo({ uni.navigateTo({
url: '/pages/ucenter/login-page/index/index' url: '/pages/ucenter/login-page/index/index'
...@@ -114,76 +113,44 @@ export default async function() { ...@@ -114,76 +113,44 @@ export default async function() {
tokenExpired tokenExpired
}) })
}) })
uni.addInterceptor('setStorage', {
invoke(args) {
if (args.data && args.key == 'uni_id_token') {
let oldToken = uni.getStorageSync('uni_id_token')
if(oldToken.length){
console.log('监听到token更新,就刷新push_clientid的有效期');
uniCloud.callFunction({
name:'uni-id-cf',
data:{
"action": "renewDeviceTokenExpiredxpired",
"params": {push_clientid}
},
complete: (e) => {
console.log(e);
}
})
}
}
// console.log('interceptor-complete', args)
},
complete(e) {
// console.log(e);
}
})
const Debug = false; const Debug = false;
//拦截器封装callFunction //拦截器封装callFunction
let callFunctionOption; let callFunctionOption;
uniCloud.addInterceptor('callFunction', { uniCloud.addInterceptor('callFunction', {
async invoke(option) { async invoke(option) {
// #ifdef APP-PLUS
// 判断如果是执行登录(无论是哪种登录方式),就记录用户的相关设备id // 判断如果是执行登录(无论是哪种登录方式),就记录用户的相关设备id
// 注意:注册可能不仅仅走register接口,还有登录并注册的接口
if (option.name == 'uni-id-cf' && if (option.name == 'uni-id-cf' &&
(option.data.action == 'register' || option.data.action.slice(0, 5) == 'login') (option.data.action == 'register' || option.data.action.slice(0, 5) == 'login')
) { ) {
let oaid = await new Promise((callBack, fail) => { option.data.deviceInfo = await getDeviceInfo()
if (uni.getSystemInfoSync().platform == "android") { console.log("重新登录/注册,获取设备id", option.data.deviceInfo);
plus.device.getOAID({
success: function(e) {
callBack(e.oaid)
// console.log('getOAID success: '+JSON.stringify(e));
},
fail: function(e) {
callBack()
console.log('getOAID failed: ' + JSON.stringify(e));
}
});
} else {
callBack()
}
})
let imei = await new Promise((callBack, fail) => {
if (uni.getSystemInfoSync().platform == "android") {
plus.device.getInfo({
success: function(e) {
callBack(e.imei)
// console.log('getOAID success: '+JSON.stringify(e));
},
fail: function(e) {
callBack()
console.log('getOAID failed: ' + JSON.stringify(e));
}
});
} else {
callBack()
}
})
let push_clientid = '',
idfa = plus.storage.getItem('idfa') || ''; //idfa有需要的用户在应用首次启动时自己获取存储到storage中
try {
push_clientid = plus.push.getClientInfo().clientid
} catch (e) {
uni.showModal({
content: '获取推送标识失败。如果你的应用不需要推送功能,请注释掉本代码块',
showCancel: false,
confirmText: "好的"
});
console.log(e)
}
let deviceInfo = {
push_clientid, // 获取匿名设备标识符
imei,
oaid,
idfa
}
//console.log("重新登录/注册,获取设备id", deviceInfo);
option.data.deviceInfo = deviceInfo
// #ifndef H5
//注册可能不仅仅走register接口,还有登录并注册的接口
option.data.inviteCode = await new Promise((callBack) => { option.data.inviteCode = await new Promise((callBack) => {
uni.getClipboardData({ uni.getClipboardData({
success: function(res) { success: function(res) {
...@@ -206,9 +173,7 @@ export default async function() { ...@@ -206,9 +173,7 @@ export default async function() {
} }
}); });
}) })
// #endif
} }
// #endif
// console.log(JSON.stringify(option)); // console.log(JSON.stringify(option));
callFunctionOption = option callFunctionOption = option
}, },
...@@ -261,7 +226,6 @@ export default async function() { ...@@ -261,7 +226,6 @@ export default async function() {
}); });
}, },
success: (e) => { success: (e) => {
// console.log(e);
const { const {
token, token,
tokenExpired tokenExpired
...@@ -455,3 +419,81 @@ function initAppVersion() { ...@@ -455,3 +419,81 @@ function initAppVersion() {
// 检查更新 // 检查更新
// #endif // #endif
} }
async function getDeviceInfo() {
let deviceInfo = {
"uuid": '',
"vendor": '',
"push_clientid": '',
"imei": '',
"oaid": '',
"idfa": '',
"model": '',
"platform": '',
}
const {
model,
platform,
} = uni.getSystemInfoSync();
Object.assign(deviceInfo, {
model,
platform
});
// #ifdef APP-PLUS
const oaid = await new Promise((callBack, fail) => {
if (deviceInfo.platform == "android") {
plus.device.getOAID({
success: function(e) {
callBack(e.oaid)
// console.log('getOAID success: '+JSON.stringify(e));
},
fail: function(e) {
callBack()
console.log('getOAID failed: ' + JSON.stringify(e));
}
});
} else {
callBack()
}
}),
{
imei,
uuid
} = await new Promise((callBack, fail) => {
plus.device.getInfo({
success: function(e) {
callBack(e)
// console.log('getOAID success: '+JSON.stringify(e));
},
fail: function(e) {
callBack()
console.log('getOAID failed: ' + JSON.stringify(e));
}
});
}),
idfa = plus.storage.getItem('idfa') || '', //idfa有需要的用户在应用首次启动时自己获取存储到storage中
vendor = plus.device.vendor;
try {
deviceInfo.push_clientid = uni.getStorageSync('cid') //先都走在线
// deviceInfo.push_clientid = plus.push.getClientInfo().clientid
} catch (e) {
uni.showModal({
content: '获取推送标识失败。如果你的应用不需要推送功能,请注释掉本代码块',
showCancel: false,
confirmText: "好的"
});
console.log(e)
}
Object.assign(deviceInfo, {
imei,
uuid,
idfa,
vendor
});
// #endif
// #ifndef APP-PLUS
deviceInfo.push_clientid = uni.getStorageSync('cid')
// #endif
return deviceInfo
}
\ No newline at end of file
...@@ -58,7 +58,6 @@ export default { ...@@ -58,7 +58,6 @@ export default {
readArticles: "Read Articles", readArticles: "Read Articles",
myScore: "My Score", myScore: "My Score",
invite: "Invite Friends", invite: "Invite Friends",
guestBook: "Guest Book Example",
feedback: "Problems And Feedback", feedback: "Problems And Feedback",
settings: "Settings", settings: "Settings",
about: "About", about: "About",
...@@ -98,14 +97,6 @@ export default { ...@@ -98,14 +97,6 @@ export default {
toSet: "Go to settings", toSet: "Go to settings",
error: "error", error: "error",
}, },
guestbook: {
navigationBarTitle:"Message board",
msgContent: "post message content",
notAvailable: "not available for visitors who are not logged in",
send: "send",
addSucceeded: "Successfully added",
noPermission: "You don't have permission for this operation",
},
uniFeedback: { uniFeedback: {
navigationBarTitle: "Problems and feedback", navigationBarTitle: "Problems and feedback",
msgTitle: "Message content", msgTitle: "Message content",
......
...@@ -59,7 +59,6 @@ export default { ...@@ -59,7 +59,6 @@ export default {
readArticles: "阅读过的文章", readArticles: "阅读过的文章",
myScore: "我的积分", myScore: "我的积分",
invite: "分销推荐", invite: "分销推荐",
guestBook: "留言板示例",
feedback: "问题与反馈", feedback: "问题与反馈",
settings: "设置", settings: "设置",
checkUpdate: "检查更新", checkUpdate: "检查更新",
...@@ -99,14 +98,6 @@ export default { ...@@ -99,14 +98,6 @@ export default {
toSet: "前往设置", toSet: "前往设置",
error: "错误", error: "错误",
}, },
guestbook:{
navigationBarTitle:"留言板",
msgContent: "发表留言内容",
notAvailable: "未登录游客不可用",
send: "发送",
addSucceeded: "新增成功",
noPermission: "你没有该操作权限",
},
uniFeedback:{ uniFeedback:{
navigationBarTitle:"问题与反馈", navigationBarTitle:"问题与反馈",
msgTitle: "留言内容", msgTitle: "留言内容",
......
{ {
"id": "uni-starter", "id": "uni-starter",
"displayName": "uni-starter", "displayName": "uni-starter",
"version": "1.1.28", "version": "1.1.29",
"description": "云端一体应用快速开发基本项目模版", "description": "云端一体应用快速开发基本项目模版",
"keywords": [ "keywords": [
"login", "login",
"登录", "登录",
"搜索", "搜索",
"uni-id实例", "uni-id实例",
"留言板", "留言板"
""
], ],
"repository": "https://codechina.csdn.net/dcloud/uni-starter.git", "repository": "https://codechina.csdn.net/dcloud/uni-starter.git",
"engines": { "engines": {
......
...@@ -169,25 +169,6 @@ ...@@ -169,25 +169,6 @@
"navigationBarTitleText": "意见反馈", "navigationBarTitleText": "意见反馈",
"enablePullDownRefresh": false "enablePullDownRefresh": false
} }
}, {
"path": "pages/ucenter/guestbook/guestbook",
"style": {
"navigationBarTitleText": "留言板",
"enablePullDownRefresh": false,
"app-plus": {
"titleNView": {
"buttons": [{
"text": "切换",
"fontSize": "12px"
},
{
"text": "注销",
"fontSize": "12px"
}
]
}
}
}
} }
], ],
"globalStyle": { "globalStyle": {
......
<template>
<view class="page">
<unicloud-db ref="udb" class="content" v-slot:default="{data,pagination,hasMore, loading, error}"
collection="guestbook,uni-id-users" :where="udbWhere" field="user_id.nickname,user_id._id,user_id.avatar_file,text,_id,state">
<view v-if="error">{{error.message}}</view>
<view v-else>
<view v-for="(item,index) in data" :key="index" class="item">
<view class="main">
<cloud-image :src="item.user_id[0].avatar_file.url"></cloud-image>
<view>
<text class="nickname">{{item.user_id[0].nickname}}</text>
<text>{{item.text}}</text>
</view>
</view>
<view class="handle">
<switch :checked="item.state" @change="setState(item,$event)" />
<uni-icons @click="deleteItem(item._id)" type="trash" size="18" color="#c9c3cd" />
</view>
</view>
<uni-load-state :state="{data,pagination,hasMore,loading}"></uni-load-state>
</view>
</unicloud-db>
<view class="submit-box">
<cloud-image class="userImg" width="60rpx" height="60rpx" v-if="userInfo.avatar_file&&userInfo.avatar_file.url" :src="userInfo.avatar_file.url"></cloud-image>
<image class="userImg" v-else src="/static/uni-center/grey.png" mode="widthFix"/>
<input class="input-box" v-model="text" :disabled="!hasLogin" :placeholder="hasLogin?$t('guestbook.msgContent'):$t('guestbook.notAvailable')" />
<button @click="text?send():''" class="btn" :class="{active:text}">{{$t('guestbook.send')}}</button>
</view>
</view>
</template>
<script>
const db = uniCloud.database();
const guestbookTable = db.collection('guestbook')
import {
mapMutations,mapGetters
} from 'vuex';
export default {
computed: {
...mapGetters({
userInfo: 'user/info',
hasLogin: 'user/hasLogin'
}),
udbWhere(){
if(this.hasLogin){
if( this.uniIDHasRole('AUDITOR') ){
return ''
}else{
return 'state==true || user_id._id==$cloudEnv_uid'
}
}else{
return '"state"==true'
}
}
},
data() {
return {
text: ""
}
},
onLoad() {
uni.setNavigationBarTitle({
title: this.$t('guestbook.navigationBarTitle')
})
},
methods: {
setState(item, e) {
item.state = e.detail.value
console.log(item, e);
this.$refs.udb.update(item._id,{
state: item.state
},{
needConfirm:false,
toastTitle: this.$t('common').updateSucceeded, // toast提示语
success: (res) => { // 新增成功后的回调
let {code,message} = res
console.log(code,message);
},
fail: (err) => { // 新增失败后的回调
let {message} = err
console.log(err);
// 判断没有权限
uni.showToast({
title:this.$t('guestbook.noPermission'),
icon: 'none'
});
this.$nextTick(() => {
item.state = !e.detail.value
})
},
complete: () => { // 完成后的回调
}
})
},
deleteItem(id) {
this.$refs.udb.remove(id, {
complete: e => {
console.log(e);
}
})
},
send() {
this.$refs.udb.add({
text: this.text
},{
toastTitle:this.$t('guestbook.addSucceeded'), // toast提示语
success: (res) => { // 新增成功后的回调
let {code,message} = res
console.log(code,message);
this.text = ''
this.$refs.udb.refresh() //{clear:true}
},
fail: (err) => { // 新增失败后的回调
let {message} = err
console.log(err);
},
complete: () => { // 完成后的回调
}
})
},
...mapMutations({
logout: 'user/logout'
}),
},
onNavigationBarButtonTap(e) {
console.log(e);
if(e.index){
this.logout()
}else{
uni.navigateTo({
url:"/pages/ucenter/login-page/index/index"
})
}
}
}
</script>
<style>
view {
display: flex;
flex-direction: column;
box-sizing: border-box;
}
.content {
padding-bottom: 110px;
}
.item {
flex-direction: row;
justify-content: space-between;
padding: 10rpx;
width: 730rpx;
margin-left: 10rpx;
border-radius: 10px;
margin-top: 10px;
}
.item .main,
.item .handle {
flex-direction: row;
align-items: center;
}
.item .main text {
padding: 0 10rpx;
color: #666666;
font-size: 24rpx;
}
.item .main .nickname {
font-weight: 600;
}
.item .handle switch {
transform: scale(0.6);
}
.submit-box {
position: fixed;
flex-direction: row;
align-items: center;
bottom: 0;
padding: 20rpx 15rpx;
width: 750rpx;
border-top: solid 1px #efecf2;
background-color: #ffffff;
height: 56px;
}
.userImg {
width: 60rpx;
height: 60rpx;
border-radius: 100px;
background-color: #f0eef4;
}
.submit-box .input-box {
background-color: #f8f8f8;
padding: 15rpx;
flex-grow: 1;
margin: 20rpx;
border-radius: 6px;
font-size: 24rpx;
}
.submit-box .btn {
height: 30px;
line-height: 30px;
font-size: 24rpx;
width: 80rpx;
padding: 0;
color: #888888;
}
.submit-box .btn::after {
display: none;
}
.submit-box .btn.active {
background-color: #007aff;
color: #FFFFFF;
}
</style>
\ No newline at end of file
...@@ -155,7 +155,7 @@ ...@@ -155,7 +155,7 @@
justify-content: flex-end; justify-content: flex-end;
} }
.captcha-img{ .captcha-img{
margin:15px 15px 0 0; margin: 0 15px 10px 0;
width: 250rpx; width: 250rpx;
} }
.captcha{ .captcha{
......
...@@ -113,10 +113,6 @@ ...@@ -113,10 +113,6 @@
// #endif // #endif
], ],
[{ [{
"title": this.$t('mine.guestBook'),
"to": '/pages/ucenter/guestbook/guestbook',
"icon": "chat"
},{
"title": this.$t('mine.feedback'), "title": this.$t('mine.feedback'),
"to": '/uni_modules/uni-feedback/pages/opendb-feedback/opendb-feedback', "to": '/uni_modules/uni-feedback/pages/opendb-feedback/opendb-feedback',
"icon": "help" "icon": "help"
......
...@@ -24,15 +24,22 @@ let state = { ...@@ -24,15 +24,22 @@ let state = {
console.log('state.info',state.info); console.log('state.info',state.info);
//存储最新的用户数据到本地持久化存储 //存储最新的用户数据到本地持久化存储
uni.setStorageSync('userInfo', state.info); uni.setStorageSync('userInfo', state.info);
uni.setStorageSync('uni_id_token', state.info.token) if(info.token){
uni.setStorageSync('uni_id_token_expired', state.info.tokenExpired) uni.setStorage({
key: 'uni_id_token',
data: state.info.token,
complete(e){
// console.log('setStorage-------',e);
}
});
uni.setStorageSync('uni_id_token_expired', state.info.tokenExpired)
}
}, },
logout(state) { logout(state) {
state.info = {}; state.info = {};
state.hasLogin = false; state.hasLogin = false;
uni.setStorageSync('userInfo', {}); uni.setStorageSync('userInfo', {});
uni.setStorageSync('uni_id_token', ''); uni.removeStorageSync('uni_id_token');
uni.setStorageSync('uni_id_token_expired', 0) uni.setStorageSync('uni_id_token_expired', 0)
} }
}, },
......
...@@ -40,7 +40,6 @@ export default { ...@@ -40,7 +40,6 @@ export default {
"/pages/common/webview/webview", "/pages/common/webview/webview",
"/pages/grid/grid", "/pages/grid/grid",
"/pages/ucenter/ucenter", "/pages/ucenter/ucenter",
"/pages/ucenter/guestbook/guestbook",
"/pages/ucenter/about/about", "/pages/ucenter/about/about",
"/pages/ucenter/settings/settings" "/pages/ucenter/settings/settings"
], ],
......
...@@ -9,4 +9,4 @@ ...@@ -9,4 +9,4 @@
// 详细JQL语法,请参考 https://uniapp.dcloud.net.cn/uniCloud/clientdb?id=jsquery // 详细JQL语法,请参考 https://uniapp.dcloud.net.cn/uniCloud/clientdb?id=jsquery
// 下面示例查询uni-id-users表的所有数据 // 下面示例查询uni-id-users表的所有数据
db.collection('guestbook, uni-id-users').where('user_id._id=="610a6daa506cc7000100c07f"').get(); db.collection('uni-id-users').where('user_id._id=="610a6daa506cc7000100c07f"').get();
// 文档教程: https://uniapp.dcloud.net.cn/uniCloud/schema
{
"bsonType": "object",
"required": [],
"permission": {
"read": "doc.state || auth.uid == doc.user_id || 'AUDITOR' in auth.role",
"create": "auth.uid != null",
"update": "'AUDITOR' in auth.role",
"delete": "auth.uid == doc.user_id"
},
"properties": {
"_id": {
"description": "ID,系统自动生成",
"permission":{
"write":false
}
},
"text": {
"bsonType": "string",
"permission":{
"write":false
}
},
"user_id": {
"forceDefaultValue": {
"$env": "uid"
},
"foreignKey": "uni-id-users._id",
"permission":{
"write":false
}
},
"ip": {
"forceDefaultValue": {
"$env": "clientIP"
},
"permission":{
"write":false
}
},
"create_time": {
"forceDefaultValue": {
"$env": "now"
},
"permission":{
"write":false
}
},
"state": {
"bsonType": "bool",
"forceDefaultValue":false,
"permission":{
"write":true
}
}
}
}
\ No newline at end of file
{ {
"goEasy": { "goEasy": {
"commonKey": "BC-01f554db12604b46ae8373907e28794d", "commonKey": "",
"clientKey": "PC-bfb6b6517e7f4c4f8b9285911fd3be27", "clientKey": "",
"subscribeKey": "BS-ac71890d8612459bb4b22429cf406be3", "subscribeKey": "",
"restKey": "PR-77f4630e731e4b5f8078aea77268cba4", "restKey": "",
"secretKey": "4bfeca3985504b3d", "secretKey": "",
"restHost":"rest-hangzhou.goeasy.io" "restHost":""
} }
} }
{
"getui": {
"appId": "dCgnx0otCL8rjloSyynDu7",
"appkey": "YGUYb5yPMN67rNyElDZv7A",
"appSecret": "b0zAa92FrG6HT9Hsqk2CR8",
"mastersecret": "nNXpI9MHkS8hZjdmQUD9H3",
"packageName": "io.dcloud.hellouniapp"
}
}
## 1.0.12(2022-01-24)
- 优化设备信息存储逻辑
- 新增刷新设备信息token有效期的API `renewDeviceTokenExpired`
## 1.0.11(2022-01-19)
- 新增 getNeedCaptcha 接口
- 优化 调整 login 接口的代码结构
## 1.0.10(2022-01-08) ## 1.0.10(2022-01-08)
- 修复 限制只有 admin 用户可管理用户标签(不支持非 admin 用户操作managerMultiTag 接口) - 修复 限制只有 admin 用户可管理用户标签(不支持非 admin 用户操作managerMultiTag 接口)
## 1.0.9(2021-12-01) ## 1.0.9(2021-12-01)
...@@ -17,8 +23,8 @@ ...@@ -17,8 +23,8 @@
## 1.0.3(2021-07-02) ## 1.0.3(2021-07-02)
- 框架设定非 admin 不能创建用户, 用户可自定义 - 框架设定非 admin 不能创建用户, 用户可自定义
## 1.0.2(2021-07-01) ## 1.0.2(2021-07-01)
1. 发送短信验证码api,默认注释掉:虚拟发送短信验证码的代码块。 - 发送短信验证码api,默认注释掉:虚拟发送短信验证码的代码块。
2. 统一action名称为驼峰法 - 统一action名称为驼峰法
## 1.0.1(2021-06-28) ## 1.0.1(2021-06-28)
修复resetPwdBySmsCode接口,未注册过的用户也能调用的问题 修复resetPwdBySmsCode接口,未注册过的用户也能调用的问题
## 1.0.0(2021-06-21) ## 1.0.0(2021-06-21)
......
{ {
"id": "uni-id-cf", "id": "uni-id-cf",
"displayName": "uni-id-cf", "displayName": "uni-id-cf",
"version": "1.0.10", "version": "1.0.12",
"description": "封装uni-id常用接口的云函数,快速实现简单、统一、可扩展的用户管理功能", "description": "封装uni-id常用接口的云函数,快速实现简单、统一、可扩展的用户管理功能",
"keywords": [ "keywords": [
"uni-id-cf", "uni-id-cf",
...@@ -78,4 +78,4 @@ ...@@ -78,4 +78,4 @@
} }
} }
} }
} }
\ No newline at end of file
...@@ -8,7 +8,11 @@ const uniIdConfig = createConfig({ ...@@ -8,7 +8,11 @@ const uniIdConfig = createConfig({
const db = uniCloud.database() const db = uniCloud.database()
const dbCmd = db.command const dbCmd = db.command
const usersDB = db.collection('uni-id-users') const usersDB = db.collection('uni-id-users')
const deviceDB = db.collection('uni-id-device')
exports.main = async (event, context) => { exports.main = async (event, context) => {
console.log({
context
});
//UNI_WYQ:这里的uniID换成新的,保证多人访问不会冲突 //UNI_WYQ:这里的uniID换成新的,保证多人访问不会冲突
uniID = uniID.createInstance({ uniID = uniID.createInstance({
context context
...@@ -16,9 +20,9 @@ exports.main = async (event, context) => { ...@@ -16,9 +20,9 @@ exports.main = async (event, context) => {
console.log('event : ' + JSON.stringify(event)) console.log('event : ' + JSON.stringify(event))
/* /*
1.event为客户端 uniCloud.callFunction填写的data的值,这里介绍一下其中的属性 1.event为客户端 uniCloud.callFunction填写的data的值,这里介绍一下其中的属性
action:表示要执行的任务名称、比如:登录login、退出登录 logout等 action:表示要执行的任务名称、比如:登录login、退出登录 logout等
params:业务数据内容 params:业务数据内容
uniIdToken:系统自动传递的token,数据来源客户端的 uni.getStorageSync('uni_id_token') uniIdToken:系统自动传递的token,数据来源客户端的 uni.getStorageSync('uni_id_token')
*/ */
const { const {
action, action,
...@@ -26,13 +30,13 @@ exports.main = async (event, context) => { ...@@ -26,13 +30,13 @@ exports.main = async (event, context) => {
inviteCode inviteCode
} = event; } = event;
const deviceInfo = event.deviceInfo || {}; const deviceInfo = event.deviceInfo || {};
let params = event.params || {}; let params = event.params || {},
tokenExpired;
/* /*
2.在某些操作之前我们要对用户对身份进行校验(也就是要检查用户的token)再将得到的uid写入params.uid 2.在某些操作之前我们要对用户对身份进行校验(也就是要检查用户的token)再将得到的uid写入params.uid
校验用到的方法是uniID.checkToken 详情:https://uniapp.dcloud.io/uniCloud/uni-id?id=checktoken 校验用到的方法是uniID.checkToken 详情:https://uniapp.dcloud.io/uniCloud/uni-id?id=checktoken
讨论,我们假设一个这样的场景,代码如下。
讨论,我们假设一个这样的场景,代码如下。 如:
如:
uniCloud.callFunction({ uniCloud.callFunction({
name:"xxx", name:"xxx",
data:{ data:{
...@@ -41,12 +45,12 @@ exports.main = async (event, context) => { ...@@ -41,12 +45,12 @@ exports.main = async (event, context) => {
} }
} }
}) })
用户就这样轻易地伪造了他人的uid传递给服务端,有一句话叫:前端传来的数据都是不可信任的 用户就这样轻易地伪造了他人的uid传递给服务端,有一句话叫:前端传来的数据都是不可信任的
所以这里我们需要将uniID.checkToken返回的uid写入到params.uid 所以这里我们需要将uniID.checkToken返回的uid写入到params.uid
*/ */
let noCheckAction = ['register', 'checkToken', 'login', 'logout', 'sendSmsCode', 'createCaptcha', let noCheckAction = ['register', 'checkToken', 'login', 'logout', 'sendSmsCode', 'getNeedCaptcha',
'verifyCaptcha', 'refreshCaptcha', 'inviteLogin', 'loginByWeixin', 'loginByUniverify', 'createCaptcha', 'verifyCaptcha', 'refreshCaptcha', 'inviteLogin', 'loginByWeixin',
'loginByApple', 'loginBySms', 'resetPwdBySmsCode', 'registerAdmin' 'loginByUniverify', 'loginByApple', 'loginBySms', 'resetPwdBySmsCode', 'registerAdmin'
] ]
if (!noCheckAction.includes(action)) { if (!noCheckAction.includes(action)) {
if (!uniIdToken) { if (!uniIdToken) {
...@@ -60,6 +64,7 @@ exports.main = async (event, context) => { ...@@ -60,6 +64,7 @@ exports.main = async (event, context) => {
return payload return payload
} }
params.uid = payload.uid params.uid = payload.uid
tokenExpired = payload.tokenExpired
} }
//禁止前台用户传递角色 //禁止前台用户传递角色
...@@ -73,7 +78,7 @@ exports.main = async (event, context) => { ...@@ -73,7 +78,7 @@ exports.main = async (event, context) => {
} }
// 3.注册成功后触发。 // 3.注册成功后触发。
async function registerSuccess(uid) { async function registerSuccess(res) {
//用户接受邀请 //用户接受邀请
if (inviteCode) { if (inviteCode) {
await uniID.acceptInvite({ await uniID.acceptInvite({
...@@ -82,18 +87,15 @@ exports.main = async (event, context) => { ...@@ -82,18 +87,15 @@ exports.main = async (event, context) => {
}); });
} }
//添加当前用户设备信息 //添加当前用户设备信息
await db.collection('uni-id-device').add({ await addDeviceInfo(res)
...deviceInfo,
user_id: uid
})
} }
//4.记录成功登录的日志方法 //4.记录成功登录的日志方法
const loginLog = async (res = {}) => { const loginLog = async (res = {}) => {
const now = Date.now() const now = Date.now()
const uniIdLogCollection = db.collection('uni-id-log') const uniIdLogCollection = db.collection('uni-id-log')
let logData = { let logData = {
deviceId: params.deviceId || context.DEVICEID, deviceId: context.DEVICEID,
ip: params.ip || context.CLIENTIP, ip: context.CLIENTIP,
type: res.type, type: res.type,
ua: context.CLIENTUA, ua: context.CLIENTUA,
create_date: now create_date: now
...@@ -106,17 +108,31 @@ exports.main = async (event, context) => { ...@@ -106,17 +108,31 @@ exports.main = async (event, context) => {
delete res.userInfo.password delete res.userInfo.password
} }
if (res.type == 'register') { if (res.type == 'register') {
await registerSuccess(res.uid) await registerSuccess(res)
} else { } else {
if (Object.keys(deviceInfo).length) { if (Object.keys(deviceInfo).length) {
// console.log(979797, { console.log(context.DEVICEID);
// deviceInfo, //避免重复新增设备信息,先判断是否已存在
// user_id: res let getDeviceRes = await deviceDB.where({
// }); device_id: context.DEVICEID
//更新当前用户设备信息 }).get()
await db.collection('uni-id-device').where({ if (getDeviceRes.data.length == 0) {
user_id: res.uid await addDeviceInfo(res)
}).update(deviceInfo) } else {
await deviceDB.where({
device_id: context.DEVICEID,
}).update({
...deviceInfo,
tokenExpired: res.tokenExpired,
"user_id": res.uid,
"device_id": context.DEVICEID,
"ua": context.CLIENTUA,
"platform": context.PLATFORM,
"create_date": Date.now(),
"last_active_date": Date.now(),
"last_active_ip": context.CLIENTIP
})
}
} }
} }
} else { } else {
...@@ -125,8 +141,55 @@ exports.main = async (event, context) => { ...@@ -125,8 +141,55 @@ exports.main = async (event, context) => {
return await uniIdLogCollection.add(logData) return await uniIdLogCollection.add(logData)
} }
async function addDeviceInfo({
uid,
tokenExpired
}) {
return await deviceDB.add({
...deviceInfo,
tokenExpired,
"user_id": uid,
"device_id": context.DEVICEID,
"ua": context.CLIENTUA,
"platform": context.PLATFORM,
"create_date": Date.now(),
"last_active_date": Date.now(),
"last_active_ip": context.CLIENTIP
})
}
//5.防止恶意破解登录,连续登录失败一定次数后,需要用户提供验证码
const isNeedCaptcha = async () => {
//当用户最近“2小时内(recordDate)”登录失败达到2次(recordSize)时。要求用户提交验证码
const now = Date.now(),
recordDate = 120 * 60 * 1000,
recordSize = 2;
const uniIdLogCollection = db.collection('uni-id-log')
let recentRecord = await uniIdLogCollection.where({
deviceId: params.deviceId || context.DEVICEID,
create_date: dbCmd.gt(now - recordDate),
type: 'login'
})
.orderBy('create_date', 'desc')
.limit(recordSize)
.get();
return recentRecord.data.filter(item => item.state === 0).length === recordSize;
}
let res = {} let res = {}
switch (action) { //根据action的值执行对应的操作 switch (action) { //根据action的值执行对应的操作
case 'renewDeviceTokenExpired':
let aa = await deviceDB.where({
user_id: params.uid,
"device_id": context.DEVICEID
}).update({
user_id: params.uid,
push_clientid: params.push_clientid,
tokenExpired
})
console.log(aa);
return aa
break;
case 'refreshSessionKey': case 'refreshSessionKey':
let getSessionKey = await uniID.code2SessionWeixin({ let getSessionKey = await uniID.code2SessionWeixin({
code: params.code code: params.code
...@@ -221,30 +284,19 @@ exports.main = async (event, context) => { ...@@ -221,30 +284,19 @@ exports.main = async (event, context) => {
inviteCode inviteCode
}); });
if (res.code === 0) { if (res.code === 0) {
await registerSuccess(res.uid) await registerSuccess(res)
} }
break; break;
case 'login':
//防止黑客恶意破解登录,连续登录失败一定次数后,需要用户提供验证码
const getNeedCaptcha = async () => {
//当用户最近“2小时内(recordDate)”登录失败达到2次(recordSize)时。要求用户提交验证码
const now = Date.now(),
recordDate = 120 * 60 * 1000,
recordSize = 2;
const uniIdLogCollection = db.collection('uni-id-log')
let recentRecord = await uniIdLogCollection.where({
deviceId: params.deviceId || context.DEVICEID,
create_date: dbCmd.gt(now - recordDate),
type: 'login'
})
.orderBy('create_date', 'desc')
.limit(recordSize)
.get();
return recentRecord.data.filter(item => item.state === 0).length === recordSize;
}
case 'getNeedCaptcha': {
const needCaptcha = await isNeedCaptcha()
res.needCaptcha = needCaptcha
break;
}
case 'login':
let passed = false; let passed = false;
let needCaptcha = await getNeedCaptcha(); let needCaptcha = await isNeedCaptcha();
console.log('needCaptcha', needCaptcha); console.log('needCaptcha', needCaptcha);
if (needCaptcha) { if (needCaptcha) {
res = await uniCaptcha.verify({ res = await uniCaptcha.verify({
...@@ -261,7 +313,7 @@ exports.main = async (event, context) => { ...@@ -261,7 +313,7 @@ exports.main = async (event, context) => {
}); });
res.type = 'login' res.type = 'login'
await loginLog(res); await loginLog(res);
needCaptcha = await getNeedCaptcha(); needCaptcha = await isNeedCaptcha();
} }
res.needCaptcha = needCaptcha; res.needCaptcha = needCaptcha;
...@@ -280,10 +332,10 @@ exports.main = async (event, context) => { ...@@ -280,10 +332,10 @@ exports.main = async (event, context) => {
} = uniIdConfig['app-plus'].oauth.weixin; } = uniIdConfig['app-plus'].oauth.weixin;
let wxRes = await uniCloud.httpclient.request( let wxRes = await uniCloud.httpclient.request(
`https://api.weixin.qq.com/sns/userinfo?access_token=${access_token}&openid=${openid}&scope=snsapi_userinfo&appid=${appid}&secret=${secret}`, { `https://api.weixin.qq.com/sns/userinfo?access_token=${access_token}&openid=${openid}&scope=snsapi_userinfo&appid=${appid}&secret=${secret}`, {
method: 'POST', method: 'POST',
contentType: 'json', // 指定以application/json发送data内的数据 contentType: 'json', // 指定以application/json发送data内的数据
dataType: 'json' // 指定返回值为json格式,自动进行parse dataType: 'json' // 指定返回值为json格式,自动进行parse
}) })
if (wxRes.status == 200) { if (wxRes.status == 200) {
let { let {
nickname, nickname,
...@@ -464,7 +516,7 @@ exports.main = async (event, context) => { ...@@ -464,7 +516,7 @@ exports.main = async (event, context) => {
}); });
break; break;
// =========================== admin api start ========================= // =========================== admin api start =========================
case 'registerAdmin': { case 'registerAdmin': {
var { var {
username, username,
...@@ -505,137 +557,137 @@ exports.main = async (event, context) => { ...@@ -505,137 +557,137 @@ exports.main = async (event, context) => {
} }
} }
break; break;
case 'registerUser': case 'registerUser':
const { const {
userInfo userInfo
} = await uniID.getUserInfo({ } = await uniID.getUserInfo({
uid: params.uid uid: params.uid
})
if (userInfo.role.indexOf('admin') === -1) {
res = {
code: 403,
message: '非法访问, 无权限注册超级管理员',
}
} else {
// 过滤 dcloud_appid,注册用户成功后再提交
const dcloudAppidList = params.dcloud_appid
delete params.dcloud_appid
res = await uniID.register({
autoSetDcloudAppid: false,
...params
}) })
if (res.code === 0) { if (userInfo.role.indexOf('admin') === -1) {
delete res.token res = {
delete res.tokenExpired code: 403,
await uniID.setAuthorizedAppLogin({ message: '非法访问, 无权限注册超级管理员',
uid: res.uid, }
dcloudAppidList } else {
// 过滤 dcloud_appid,注册用户成功后再提交
const dcloudAppidList = params.dcloud_appid
delete params.dcloud_appid
res = await uniID.register({
autoSetDcloudAppid: false,
...params
}) })
if (res.code === 0) {
delete res.token
delete res.tokenExpired
await uniID.setAuthorizedAppLogin({
uid: res.uid,
dcloudAppidList
})
}
} }
} break;
break; case 'updateUser': {
case 'updateUser': { const {
const { userInfo
userInfo } = await uniID.getUserInfo({
} = await uniID.getUserInfo({ uid: params.uid
uid: params.uid })
}) if (userInfo.role.indexOf('admin') === -1) {
if (userInfo.role.indexOf('admin') === -1) { res = {
res = { code: 403,
code: 403, message: '非法访问, 无权限注册超级管理员',
message: '非法访问, 无权限注册超级管理员', }
} } else {
} else { // 过滤 dcloud_appid,注册用户成功后再提交
// 过滤 dcloud_appid,注册用户成功后再提交 const dcloudAppidList = params.dcloud_appid
const dcloudAppidList = params.dcloud_appid delete params.dcloud_appid
delete params.dcloud_appid
// 过滤 password,注册用户成功后再提交 // 过滤 password,注册用户成功后再提交
const password = params.password const password = params.password
delete params.password delete params.password
// 过滤 uid、id // 过滤 uid、id
const id = params.id const id = params.id
delete params.id delete params.id
delete params.uid delete params.uid
res = await uniID.updateUser({ res = await uniID.updateUser({
uid: id, uid: id,
...params ...params
}) })
if (res.code === 0) { if (res.code === 0) {
if (password) { if (password) {
await uniID.resetPwd({ await uniID.resetPwd({
uid: id,
password
})
}
await uniID.setAuthorizedAppLogin({
uid: id, uid: id,
password dcloudAppidList
}) })
} }
await uniID.setAuthorizedAppLogin({
uid: id,
dcloudAppidList
})
}
}
break;
}
case 'getCurrentUserInfo':
res = await uniID.getUserInfo({
uid: params.uid,
...params
})
break;
case 'managerMultiTag': {
const {
userInfo
} = await uniID.getUserInfo({
uid: params.uid
})
// 限制只有 admin 角色的用户可管理标签,如需非 admin 角色需自行实现
if (userInfo.role.indexOf('admin') === -1) {
res = {
code: 403,
message: '非法访问, 无权限修改用户标签',
} }
return break;
} }
let { case 'getCurrentUserInfo':
ids, res = await uniID.getUserInfo({
type, uid: params.uid,
value ...params
} = params
if (type === 'add') {
res = await db.collection('uni-id-users').where({
_id: dbCmd.in(ids)
}).update({
tags: dbCmd.addToSet({
$each: value
})
}) })
} else if (type === 'del') { break;
res = await db.collection('uni-id-users').where({ case 'managerMultiTag': {
_id: dbCmd.in(ids) const {
}).update({ userInfo
tags: dbCmd.pull(dbCmd.in(value)) } = await uniID.getUserInfo({
uid: params.uid
}) })
} else { // 限制只有 admin 角色的用户可管理标签,如需非 admin 角色需自行实现
if (userInfo.role.indexOf('admin') === -1) {
res = {
code: 403,
message: '非法访问, 无权限修改用户标签',
}
return
}
let {
ids,
type,
value
} = params
if (type === 'add') {
res = await db.collection('uni-id-users').where({
_id: dbCmd.in(ids)
}).update({
tags: dbCmd.addToSet({
$each: value
})
})
} else if (type === 'del') {
res = await db.collection('uni-id-users').where({
_id: dbCmd.in(ids)
}).update({
tags: dbCmd.pull(dbCmd.in(value))
})
} else {
res = {
code: 403,
msg: '无效操作'
}
return
}
break;
}
// =========================== admin api end =========================
default:
res = { res = {
code: 403, code: 403,
msg: '无效操作' msg: '非法访问'
} }
return break;
}
break;
}
// =========================== admin api end =========================
default:
res = {
code: 403,
msg: '非法访问'
}
break;
} }
//返回数据给客户端 //返回数据给客户端
return res return res
} }
\ No newline at end of file
## 3.3.12(2022-01-15)
- 新增 preferedAppPlatform 配置用于解决uni-app vue2版本vue3版本获取platform不一致的问题 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=prefered-app-platform)
- 修复 checkToken 未返回自定义token内容的Bug
## 3.3.11(2022-01-11) ## 3.3.11(2022-01-11)
- 修复用户名密码登录时多个应用出现重复用户名登录报错的Bug - 修复用户名密码登录时多个应用出现重复用户名登录报错的Bug
## 3.3.10(2022-01-07) ## 3.3.10(2022-01-07)
......
{ {
"id": "uni-id", "id": "uni-id",
"displayName": "uni-id", "displayName": "uni-id",
"version": "3.3.11", "version": "3.3.12",
"description": "简单、统一、可扩展的用户中心", "description": "简单、统一、可扩展的用户中心",
"keywords": [ "keywords": [
"uniid", "uniid",
......
{ {
"name": "uni-id", "name": "uni-id",
"version": "3.3.11", "version": "3.3.12",
"description": "uni-id for uniCloud", "description": "uni-id for uniCloud",
"main": "index.js", "main": "index.js",
"homepage": "https://uniapp.dcloud.io/uniCloud/uni-id", "homepage": "https://uniapp.dcloud.io/uniCloud/uni-id",
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册