提交 830bddfa 编写于 作者: 芊里

Merge branch 'master' of https://gitee.com/dcloud/base-app

...@@ -187,6 +187,27 @@ ...@@ -187,6 +187,27 @@
"navigationBarBackgroundColor": "#FFFFFF", "navigationBarBackgroundColor": "#FFFFFF",
"backgroundColor": "#F8F8F8" "backgroundColor": "#F8F8F8"
}, },
"condition": {
"list": [{
"path": "uni_modules/uni-login-page/pages/index/index",
"style": {
"navigationBarTitleText": "",
"app-plus": {
"animationType": "none",
"popGesture": "none",
"titleNView": {
"buttons": [{
"text": "帮助",
"type": "none",
"fontSize": "16px",
"width": "60px"
}]
}
}
}
}],
"current": 0
},
"tabBar": { "tabBar": {
"color": "#7A7E83", "color": "#7A7E83",
"selectedColor": "#007AFF", "selectedColor": "#007AFF",
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
} from 'vuex'; } from 'vuex';
const db = uniCloud.database(); const db = uniCloud.database();
const userTable = db.collection('uni-id-users')
export default { export default {
data() { data() {
return { return {
...@@ -60,9 +61,7 @@ ...@@ -60,9 +61,7 @@
* value 更新后的用户字段值 * value 更新后的用户字段值
*/ */
uploadUserInfo(data){ uploadUserInfo(data){
db.collection('uni-id-users').where({ userTable.doc(this.userInfo._id)
_id: this.userInfo._id
})
.update(data) .update(data)
.then(res=>{ .then(res=>{
console.log(res); console.log(res);
......
...@@ -14,14 +14,14 @@ ...@@ -14,14 +14,14 @@
</uni-grid-item> </uni-grid-item>
</uni-grid> </uni-grid>
<uni-list class="center-list" v-for="(sublist , index) in ucenterList"> <uni-list class="center-list" v-for="(sublist , index) in ucenterList">
<uni-list-item v-for="item in sublist" <uni-list-item v-for="item in sublist"
:title="item.title" :title="item.title"
link :rightText="item.rightText" link :rightText="item.rightText"
:clickable="true" :clickable="true"
:to="item.to" :to="item.to"
@click="ucenterListClick(item)" @click="ucenterListClick(item)"
></uni-list-item> ></uni-list-item>
</uni-list> </uni-list>
</view> </view>
</template> </template>
...@@ -58,10 +58,10 @@ ...@@ -58,10 +58,10 @@
], ],
ucenterList: [ ucenterList: [
[{ [{
title: '阅读过的文章', title: '阅读过的文章',
to: '' to: ''
}, { }, {
title: '我的积分', title: '我的积分',
to: '' to: ''
}], }],
[{ [{
...@@ -125,12 +125,12 @@ ...@@ -125,12 +125,12 @@
url: './edit/edit' url: './edit/edit'
}) })
} }
}, },
tapGrid(index){ tapGrid(index){
uni.showToast({ uni.showToast({
title: '你点击了,第'+index+'', title: '你点击了,第'+index+'',
icon: 'none' icon: 'none'
}); });
} }
} }
} }
...@@ -167,7 +167,7 @@ ...@@ -167,7 +167,7 @@
.userInfo { .userInfo {
width: 750rpx; width: 750rpx;
padding: 20rpx; padding: 20rpx;
padding-top:50px; padding-top:50px;
background-color: #2F85FC; background-color: #2F85FC;
flex-direction: column; flex-direction: column;
...@@ -181,7 +181,7 @@ ...@@ -181,7 +181,7 @@
.logo-img { .logo-img {
width: 150rpx; width: 150rpx;
height: 150rpx; height: 150rpx;
border-radius: 150rpx; border-radius: 150rpx;
border: solid 1px #FFFFFF; border: solid 1px #FFFFFF;
} }
...@@ -216,20 +216,20 @@ ...@@ -216,20 +216,20 @@
font-family: texticons; font-family: texticons;
} }
.center-list { .center-list {
margin-bottom: 30rpx; margin-bottom: 30rpx;
background-color: #f9f9f9; background-color: #f9f9f9;
} }
.center-list-cell { .center-list-cell {
width: 750rpx; width: 750rpx;
background-color: #007AFF; background-color: #007AFF;
height: 40rpx; height: 40rpx;
} }
.grid{ .grid{
background-color: #FFFFFF; background-color: #FFFFFF;
margin:25rpx 0; margin:25rpx 0;
} }
.uni-grid .text { .uni-grid .text {
font-size: 26rpx; font-size: 26rpx;
...@@ -239,17 +239,17 @@ ...@@ -239,17 +239,17 @@
.uni-grid .item /deep/ .uni-grid-item__box { .uni-grid .item /deep/ .uni-grid-item__box {
justify-content: center; justify-content: center;
align-items: center; align-items: center;
} }
/*修改边线粗细示例*/ /*修改边线粗细示例*/
/* #ifndef APP-NVUE */ /* #ifndef APP-NVUE */
.center-list /deep/ .uni-list--border:after, .center-list /deep/ .uni-list--border:after,
.center-list /deep/ .uni-list--border-top , .center-list /deep/ .uni-list--border-top ,
.center-list /deep/ .uni-list--border-bottom{ .center-list /deep/ .uni-list--border-bottom{
-webkit-transform: scaleY(0.2); -webkit-transform: scaleY(0.2);
transform: scaleY(0.2); transform: scaleY(0.2);
} }
/* #endif */ /* #endif */
</style> </style>
{
"name": "user-center",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"uni-captcha": {
"version": "file:../../../uni_modules/uni-captcha/uniCloud/cloudfunctions/common/uni-captcha"
},
"uni-id": {
"version": "file:../../../uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id"
}
}
}
{
"name": "user-center",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"uni-captcha": "file:../../../uni_modules/uni-captcha/uniCloud/cloudfunctions/common/uni-captcha",
"uni-id": "file:../../../uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id"
}
}
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
"permission": { "permission": {
"read": true, "read": true,
"create": false, "create": false,
"update": "doc.uid == auth.uid", "update": "doc._id == auth.uid",
"delete": false "delete": false
}, },
"properties": { "properties": {
......
...@@ -44,13 +44,9 @@ ...@@ -44,13 +44,9 @@
"smsSecret": "d6c424b702d73baa3b6e1a1452469213" "smsSecret": "d6c424b702d73baa3b6e1a1452469213"
}, },
"univerify":{ "univerify":{
// "appid": "__UNI__GameCat", "appid": "__UNI__GameCat",
// "apiKey":"c5f80ebad34aaf0ae22958d866287521", "apiKey":"c5f80ebad34aaf0ae22958d866287521",
// "apiSecret":"f921890ca9c248273eadaf9b4137cf5c" "apiSecret":"f921890ca9c248273eadaf9b4137cf5c"
"appid": "__UNI__BC54A00",
"apiKey":"d1e36bcd497b3795434d900dcfdd44dc",
"apiSecret":"2feb378ff1114362b20ac179b572293e"
} }
} }
} }
<template> <template>
<view class="quick-login-box"> <view class="quick-login-box">
<view class="item" v-for="({text,logo,name},index) in providerList" :key="index" @click="login(name)"> <view class="item" v-for="({id},index) in oauthServices" :key="index" @click="login(id)" v-if="config[id].isChecked">
<image class="logo" :src="logo" mode="widthFix"></image> <image class="logo" :src="config[id].logo" mode="widthFix"></image>
<text class="login-title">{{text}}</text> <text class="login-title">{{config[id].text}}</text>
</view> </view>
</view> </view>
</template> </template>
...@@ -14,37 +14,61 @@ ...@@ -14,37 +14,61 @@
config: { config: {
"weixin": { "weixin": {
"text": "微信登陆", "text": "微信登陆",
"logo": "../../static/login/img/weixin.png" "logo": "../../static/login/img/weixin.png",
"isChecked":true
}, },
"apple": {
"text": "苹果登陆",
"logo": "../../static/login/img/apple.png",
"isChecked":true
},
"univerify": {
"text": "一键登陆",
"logo": "../../static/login/img/univerify.png",
"isChecked":true
},
"qq": { "qq": {
"text": "QQ登陆", "text": "QQ登陆",
"logo": "../../static/login/img/qq.png" "logo": "../../static/login/img/qq.png",
"isChecked":false //暂未提供该登陆方式的接口示例
}, },
"xiaomi": { "xiaomi": {
"text": "小米登陆", "text": "小米登陆",
"logo": "../../static/login/img/qq.png" "logo": "../../static/login/img/qq.png",
}, "isChecked":false //暂未提供该登陆方式的接口示例
"apple": {
"text": "苹果登陆",
"logo": "../../static/login/img/apple.png"
}, },
"sinaweibo": { "sinaweibo": {
"text": "微博登录", "text": "微博登录",
"logo": "../../static/login/img/sinaweibo.png" "logo": "../../static/login/img/sinaweibo.png",
"isChecked":false //暂未提供该登陆方式的接口示例
}, },
"univerify": {
"text": "一键登陆",
"logo": "../../static/login/img/univerify.png"
}
}, },
providerList: [], providerList: [],
oauthServices:[],
univerifyStyle: { univerifyStyle: {
"fullScreen": true, // 是否全屏显示,true表示全屏模式,false表示非全屏模式,默认值为false。 "fullScreen": true, // 是否全屏显示,true表示全屏模式,false表示非全屏模式,默认值为false。
"backgroundColor": "#ffffff", // 授权页面背景颜色,默认值:#ffffff "backgroundColor": "#ffffff", // 授权页面背景颜色,默认值:#ffffff
} }
} }
}, },
mounted() { mounted() {
//获取当前环境能用的快捷登陆方式
// #ifdef APP-PLUS
plus.oauth.getServices(oauthServices=>{
this.oauthServices = oauthServices
console.log(oauthServices);
},err=>{
uni.showModal({
title: '获取服务供应商失败:' +JSON.stringify(err),
showCancel: false,
confirmText: '知道了'
});
console.error('获取服务供应商失败:' + JSON.stringify(err));
})
// #endif
/*
uni.getProvider({ uni.getProvider({
"service": "oauth", "service": "oauth",
success: res => { success: res => {
...@@ -57,11 +81,20 @@ ...@@ -57,11 +81,20 @@
console.error('获取服务供应商失败:' + JSON.stringify(err)); console.error('获取服务供应商失败:' + JSON.stringify(err));
} }
}) })
*/
}, },
methods: { methods: {
login(type) { login(type) {
// #ifndef H5 let oauthService = this.oauthServices.find((service) => service.id == type)
// #ifdef APP-PLUS
uni.showLoading({mask: true}); uni.showLoading({mask: true});
if(type=='weixin'){
oauthService.authorize(({code})=>{
console.log(code);
this.quickLogin({code},type)
})
}
uni.login({ uni.login({
"provider": type, "provider": type,
"univerifyStyle":this.univerifyStyle, "univerifyStyle":this.univerifyStyle,
...@@ -77,21 +110,24 @@ ...@@ -77,21 +110,24 @@
uni.hideLoading() uni.hideLoading()
console.log(err); console.log(err);
if(err.errCode===30002){ if(err.errCode===30002){
console.log('你手动关闭了,一键登陆'); console.log('在一键登陆界面,点击其他登陆方式');
}
if(err.errCode===30003){
uni.navigateBack()
} }
} }
}) })
// #endif // #endif
}, },
quickLogin(authResult,type){ quickLogin(params,type){
//请勿直接使用authResult中的unionid或openid直接用于登陆,前端的数据都是不可靠的 //请勿直接使用authResult中的unionid或openid直接用于登陆,前端的数据都是不可靠的
console.log({...authResult,type}); console.log({params,type});
uniCloud.callFunction({//联网验证登陆 uniCloud.callFunction({//联网验证登陆
"name": "user", "name": "user-center",
"data": { "data": {
"action": "quickLogin", "action": "login_by_"+type,
"params": {...authResult,type} params
}, },
success: (e) => { success: (e) => {
console.log(e.result); console.log(e.result);
......
...@@ -3,37 +3,17 @@ const uniID = require('uni-id') ...@@ -3,37 +3,17 @@ const uniID = require('uni-id')
const uniCaptcha = require('uni-captcha') const uniCaptcha = require('uni-captcha')
const db = uniCloud.database() const db = uniCloud.database()
const dbCmd = db.command const dbCmd = db.command
exports.main = async (event, context) => { exports.main = async (event, context) => {
let params = event.params || {} //event为客户端上传的参数
// 登录记录 console.log('event : ' + event)
const loginLog = async (res = {}, type = 'login') => { let params = event.params || {}
const now = Date.now()
const uniIdLogCollection = db.collection('uni-id-log') //防止黑客恶意破解登陆,连续登陆失败一定次数后,需要用户提供验证码
let logData = { const getNeedCaptcha = async () => {
deviceId: params.deviceId || context.DEVICEID, //当用户最近“2小时内(recordDate)”登陆失败达到2次(recordSize)时。要求用户提交验证码
ip: params.ip || context.CLIENTIP, const now = Date.now(),
type, recordDate = 120 * 60 * 1000,
ua: context.CLIENTUA, recordSize = 2;
create_date: now
};
Object.assign(logData,
res.code === 0 ? {
user_id: res.uid,
state: 1
} : {
state: 0
})
return uniIdLogCollection.add(logData)
}
const getNeedCaptcha = async () => {
const now = Date.now()
// 查询是否在 {2小时} 内 {前2条} 有 {登录失败} 数据,来确定是否需要验证码
const recordSize = 2;
const recordDate = 120 * 60 * 1000;
const uniIdLogCollection = db.collection('uni-id-log') const uniIdLogCollection = db.collection('uni-id-log')
let recentRecord = await uniIdLogCollection.where({ let recentRecord = await uniIdLogCollection.where({
deviceId: params.deviceId || context.DEVICEID, deviceId: params.deviceId || context.DEVICEID,
...@@ -43,38 +23,57 @@ exports.main = async (event, context) => { ...@@ -43,38 +23,57 @@ exports.main = async (event, context) => {
.orderBy('create_date', 'desc') .orderBy('create_date', 'desc')
.limit(recordSize) .limit(recordSize)
.get(); .get();
return recentRecord.data.filter(item => item.state === 0).length === recordSize; return recentRecord.data.filter(item => item.state === 0).length === recordSize;
} }
//event为客户端上传的参数 //设置某些模块不需要token(也就是登陆成功后)才能操作,如果需要token就获取当前操作账户的uid
console.log('event : ' + event)
let payload = {}
let noCheckAction = [ let noCheckAction = [
'register', 'loginByWeixin', 'checkToken', 'register', 'checkToken','login', 'logout', 'sendSmsCode',
'login', 'logout', 'sendSmsCode', 'createCaptcha', 'verifyCaptcha','refreshCaptcha', 'inviteLogin',
'loginBySms', 'inviteLogin', 'loginByUniverify', 'login_by_weixin','login_by_univerify','login_by_apple','loginBySms'
'loginByApple', 'createCaptcha', 'verifyCaptcha', ]
'refreshCaptcha' console.log(event.action);
] if (!noCheckAction.includes(event.action)) {
if (noCheckAction.indexOf(event.action) === -1) {
if (!event.uniIdToken) { if (!event.uniIdToken) {
return { return {
code: 403, code: 403,
msg: '缺少token' msg: '缺少token'
} }
} }
payload = await uniID.checkToken(event.uniIdToken) let payload = await uniID.checkToken(event.uniIdToken)
if (payload.code && payload.code > 0) { if (payload.code && payload.code > 0) {
return payload return payload
} }
params.uid = payload.uid params.uid = payload.uid
}
//记录成功登陆的日志
const loginLog = async (res = {}, type = 'login') => {
const now = Date.now()
const uniIdLogCollection = db.collection('uni-id-log')
let logData = {
deviceId: params.deviceId || context.DEVICEID,
ip: params.ip || context.CLIENTIP,
type,
ua: context.CLIENTUA,
create_date: now
};
Object.assign(logData,
res.code === 0 ? {
user_id: res.uid,
state: 1
} : {
state: 0
})
return uniIdLogCollection.add(logData)
} }
let res = {} let res = {}
switch (event.action) { switch (event.action) {
case 'register': case 'register':
res = await uniID.register(params); res = await uniID.register(params);
...@@ -95,10 +94,17 @@ exports.main = async (event, context) => { ...@@ -95,10 +94,17 @@ exports.main = async (event, context) => {
} }
res.needCaptcha = needCaptcha; res.needCaptcha = needCaptcha;
break; break;
case 'loginByWeixin': case 'login_by_weixin':
res = await uniID.loginByWeixin(params); res = await uniID.loginByWeixin(params);
loginLog(res) loginLog(res)
break;
case 'login_by_univerify':
res = await uniID.loginByUniverify(params)
break;
case 'login_by_apple':
res = await uniID.loginByApple(params)
loginLog(res)
break; break;
case 'checkToken': case 'checkToken':
res = await uniID.checkToken(event.uniIdToken); res = await uniID.checkToken(event.uniIdToken);
...@@ -175,13 +181,6 @@ exports.main = async (event, context) => { ...@@ -175,13 +181,6 @@ exports.main = async (event, context) => {
case 'getInvitedUser': case 'getInvitedUser':
res = await uniID.getInvitedUser(params) res = await uniID.getInvitedUser(params)
break; break;
case 'loginByUniverify':
res = await uniID.loginByUniverify(params)
break;
case 'loginByApple':
res = await uniID.loginByApple(params)
loginLog(res)
break;
case 'updatePwd': case 'updatePwd':
res = await uniID.updatePwd({ res = await uniID.updatePwd({
uid: params.uid, uid: params.uid,
......
{ {
"name": "user", "name": "user-center",
"version": "1.0.0", "version": "1.0.0",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
......
{ {
"name": "user", "name": "user-center",
"version": "1.0.0", "version": "1.0.0",
"description": "", "description": "",
"main": "index.js", "main": "index.js",
......
'use strict';
const uniID = require('uni-id')
const uniCaptcha = require('uni-captcha')
const db = uniCloud.database()
const dbCmd = db.command
let params,context,res;
class User {
async quickLogin(){
let {access_token,openid,type} = params
switch (type){
case 'weixin':
let userinfo_res = await uniCloud.httpclient.request('https://api.weixin.qq.com/sns/userinfo',
{
method: 'GET',
dataType:"json",
data:{ access_token,openid}
});
return userinfo_res.data//根据access_token,openid得到userinfo
//检查是否已经注册...待续...
break;
case 'univerify':
return uniID.loginByUniverify({access_token,openid})
break;
case 'apple':
return await uniID.loginByApple(params)
break;
default:
return {"code":100,"msg":"暂不提供"+type+"登陆的云端接口演示"}
break;
}
}
async sendSmsCode(){
// 简单限制一下客户端调用频率
const ipLimit = await db.collection('uni-verify').where({
ip: context.CLIENTIP,
created_at: dbCmd.gt(Date.now() - 60000)
}).get()
if (ipLimit.data.length > 0) {
return {
code: 429,
msg: '请求过于频繁'
}
}
const templateId = '11753' // 替换为自己申请的模板id
if (!templateId) {
return {
code: 500,
msg: 'sendSmsCode需要传入自己的templateId,参考https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=sendsmscode'
}
}
const randomStr = '00000' + Math.floor(Math.random() * 1000000)
const code = randomStr.substring(randomStr.length - 6)
return await uniID.sendSmsCode({
mobile: params.mobile,
code,
type: params.type,
templateId
})
}
}
const userClass = new User();
exports.main = async (event, ctx) => {
[{params},context] = [event,ctx]
//1.判断需要token的action是否有token
/*let noCheckAction = ['register', 'loginByWeixin', 'checkToken','login', 'logout', 'sendSmsCode','loginBySms', 'inviteLogin', 'loginByUniverify','loginByApple', 'createCaptcha', 'verifyCaptcha','refreshCaptcha']
if(!noCheckAction.includes(event.action)) {
if (!event.uniIdToken) {
return {"code":403,"msg":"缺少token"}
}
let payload = {}
payload = await uniID.checkToken(event.uniIdToken)
if (payload.code && payload.code > 0) {
return payload
}
params.uid = payload.uid
}*/
try{
return await userClass[event.action]()||res;
}catch(err){
return {"code":404,"msg":err}
}
}
\ No newline at end of file
// 本文件中的json内容将在云函数【运行】时作为参数传给云函数。
// 配置教程参考:https://uniapp.dcloud.net.cn/uniCloud/quickstart?id=runparam
{
"action": "sendSmsCode",
"params": {
"mobile":"17769516081",
"type":"register"
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册