day108:MoFang:首頁檢測用戶是否登錄&在項目中使用MongoDB&用戶頁面更新用戶資訊&交易密碼介面實現
- 2020 年 12 月 11 日
- 筆記
- PythonS31-筆記, Python全棧31期-筆記
目錄
1.首頁頁面也要檢測用戶是否登錄
created(){ this.check_user_login(); }, methods:{ // 首頁檢測用戶是否登錄 check_user_login(){ let token = this.game.get("access_token") || this.game.fget("access_token"); this.game.checkout(this, token, (new_access_token)=>{ if(new_access_token.errno == 1005){ this.game.save({"access_token":""}); this.game.fremove("access_token"); } }); },
2.修改main.js中checkout函數
當檢查用戶登錄狀態時,如果用戶點擊取消登錄,則返回1005狀態碼.
class Game{ // 驗證用戶token是否存在或者是否失效的功能 checkout(vm, token, callback){ vm.axios.post("",{ "jsonrpc": "2.0", "id": vm.uuid(), "method": "User.check", "params": {} },{ headers:{ Authorization: "jwt " + token, } }).then(response=>{ if(parseInt(response.data.result.errno) === 1005){ api.actionSheet({ title: '本次登陸超時,是否更新登陸狀態?', cancelTitle: '取消登陸', destructiveTitle: '更新登陸狀態', }, (ret, err)=>{ if( ret.buttonIndex == 1 ){ this.get_acccess_by_refresh(vm, callback); }else{ // ******** callback({"errno":1005,"errmsg":"登陸超時!"}); } }); }else if (parseInt(response.data.result.errno) === 1000){ callback(token); } return false; }).catch(error=>{ this.print(error); }); } get_acccess_by_refresh(vm, callback){ var token = this.get("refresh_token") || this.fget("refresh_token"); if( !token ){ return false; } vm.axios.post("",{ "jsonrpc": "2.0", "id": vm.uuid(), "method": "User.refresh", "params": {} },{ headers:{ Authorization: "jwt " + token, } }).then(response=>{ if(response.data.result.errno===1000){ this.save({"access_token": response.data.result.access_token}); callback(response.data.result.access_token); } }) }
2.在flask中使用MongoDB
1.安裝
pip install Flask-PyMongo
2.初始化和配置
from flask_pymongo import PyMongo # mongoDB mongo = PyMongo() def init_app(config_path): """全局初始化""" # 資料庫初始化 db.init_app(app) app.db = db redis.init_app(app) mongo.init_app(app) # 初始化mongo
from . import InitConfig class Config(InitConfig): """項目開發環境下的配置""" # mongoDB配置資訊 MONGO_URI = "mongodb://127.0.0.1:27017/mofang"
import base64, uuid,os from application import mongo from datetime import datetime @jsonrpc.method("User.avatar.update") @jwt_required # 驗證jwt def update_avatar(avatar): """獲取用戶資訊""" # 1. 接受客戶端上傳的頭像資訊 ext = avatar[avatar.find("/")+1:avatar.find(";")] # 資源格式 b64_avatar = avatar[avatar.find(",")+1:] b64_image = base64.b64decode(b64_avatar) filename = uuid.uuid4() static_path = os.path.join( current_app.BASE_DIR,current_app.config["STATIC_DIR"] ) with open("%s/%s.%s" % (static_path, filename,ext),"wb") as f: f.write(b64_image) # 2.判斷用戶是否存在 current_user_id = get_jwt_identity() user = User.query.get(current_user_id) if user is None: return { "errno": status.CODE_NO_USER, "errmsg": message.user_not_exists, } # 3.將用戶頭像存到mysql資料庫中 user.avatar = "%s.%s" % (filename,ext) db.session.commit() # ***4.添加修改記錄到MongoDB***! document = { "user_id": user.id, "user_name": user.name, "user_nikcname": user.nickname, "updated_time": datetime.now().timestamp(), # 修改時間 "avatar": avatar, # 圖片內容 "type": "avatar", # 本次操作的類型 } mongo.db.user_info_history.insert_one(document) return { "errno": status.CODE_OK, "errmsg": message.avatar_save_success, "avatar": "%s.%s" % (filename,ext) }
3.用戶頁面更新用戶資訊
2.並且在user.html中添加之前已經寫過的change_avatar函數和get_user_info函數
<!DOCTYPE html> <html> <head> <title>用戶中心</title> <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"> <meta charset="utf-8"> <link rel="stylesheet" href="../static/css/main.css"> <script src="../static/js/vue.js"></script> <script src="../static/js/axios.js"></script> <script src="../static/js/main.js"></script> <script src="../static/js/uuid.js"></script> <script src="../static/js/settings.js"></script> </head> <body> <div class="app user" id="app"> <div class="bg"> <img src="../static/images/bg0.jpg"> </div> <img class="back" @click="goto_index" src="../static/images/user_back.png" alt=""> <img class="setting" @click="goto_setting" src="../static/images/setting.png" alt=""> <div class="header"> <div class="info"> <div class="avatar"> <img class="avatar_bf" src="../static/images/avatar_bf.png" alt=""> <img class="user_avatar" :src="avatar" alt=""> <img class="avatar_border" src="../static/images/avatar_border.png" alt=""> </div> <p class="user_name">{{nickname}}</p> </div> <div class="wallet"> <div class="balance"> <p class="title"><img src="../static/images/money.png" alt="">錢包</p> <p class="num">99,999.00</p> </div> <div class="balance"> <p class="title"><img src="../static/images/integral.png" alt="">果子</p> <p class="num">99,999.00</p> </div> </div> <div class="invite"> <img class="invite_btn" src="../static/images/invite.png" alt=""> </div> </div> <div class="menu"> <div class="item"> <span class="title">我的主頁</span> <span class="value">查看</span> </div> <div class="item"> <span class="title">任務列表</span> <span class="value">75%</span> </div> <div class="item"> <span class="title">收益明細</span> <span class="value">查看</span> </div> <div class="item"> <span class="title">實名認證</span> <span class="value">未認證</span> </div> <div class="item"> <span class="title">問題回饋</span> <span class="value">去回饋</span> </div> </ul> </div> </div> <script> apiready = function(){ init(); new Vue({ el:"#app", data(){ return { nickname:"", avatar:"", prev:{name:"",url:"",params:{}}, current:{name:"user",url:"user.html",params:{}}, } }, created(){ this.get_user_info(); this.change_avatar(); }, methods:{ change_avatar(){ api.addEventListener({ name: 'change_avatar' }, (ret, err)=>{ if( ret ){ var token = this.game.get("access_token") || this.game.fget("access_token"); this.avatar = `${this.settings.avatar_url}?sign=${ret.value.avatar}&token=${token}`; } }); }, get_user_info(){ var token = this.game.get("access_token") || this.game.fget("access_token"); // 獲取當前登陸用戶基本資訊 this.axios.post("",{ "jsonrpc": "2.0", "id": this.uuid(), "method": "User.info", "params": {} },{ headers:{ Authorization: "jwt " + token, } }).then(response=>{ var res = response.data.result; this.game.print(res); if(parseInt(res.errno) === 1000){ this.nickname = res.nickname; this.avatar = `${this.settings.avatar_url}?sign=${res.avatar}&token=${token}`; } }) }, goto_index(){ // 返回首頁 this.game.outWin("user"); }, goto_setting(){ // 進入設置 this.game.goFrame("setting","setting.html", this.current); } } }); } </script> </body> </html>
用戶頁面更新用戶資訊
解決頭像圓角問題
.user .info .user_avatar{ position: absolute; z-index: 1; width: 4.56rem; height: 4.56rem; margin: auto; top: 0; bottom: 0; left: 0; right: 0; border-radius: 1rem; }
4.交易密碼介面/密碼修改介面/昵稱修改介面初始化
1.配置頁面點擊交易/密碼修改/昵稱,進入到相應介面
<!DOCTYPE html> <html> <head> <title>用戶中心</title> <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"> <meta charset="utf-8"> <link rel="stylesheet" href="../static/css/main.css"> <script src="../static/js/vue.js"></script> <script src="../static/js/axios.js"></script> <script src="../static/js/main.js"></script> <script src="../static/js/uuid.js"></script> <script src="../static/js/settings.js"></script> </head> <body> <div class="app user setting" id="app"> <div class="bg"> <img src="../static/images/form_bg.png"> </div> <img class="back" @click="goto_home" src="../static/images/user_back.png" alt=""> <div class="form"> <div class="item avatar" @click="update_avatar_frame"> <span class="title">頭像</span> <span class="goto">></span> <span class="value"> <img :src="avatar" alt=""> </span> </div> <div class="item" @click="update_nickname_frame"> <span class="title">昵稱</span> <span class="goto">></span> <span class="value">{{nickname}}</span> </div> <div class="item"> <span class="title">手機號</span> <span class="goto">></span> <span class="value">{{mobile}}</span> </div> <div class="item" @click="update_password_frame"> <span class="title">登陸密碼</span> <span class="value"></span> <span class="goto">></span> </div> <div class="item" @click="update_transaction_password_frame"> <span class="title">交易密碼</span> <span class="value"></span> <span class="goto">></span> </div> <div class="item"> <span class="title">地址管理</span> <span class="value"></span> <span class="goto">></span> </div> <div class="item"> <span class="title">設備管理</span> <span class="value"></span> <span class="goto">></span> </div> <div class="item logout"> <img @click="change_account" src="../static/images/change_account.png" alt=""> <p @click="logout">退出帳號</p> </div> </div> </div> <script> apiready = function(){ init(); new Vue({ el:"#app", data(){ return { nickname: "", mobile: "", avatar: "../static/images/avatar.png", prev:{name:"",url:"",params:{}}, current:{name:"setting",url:"setting.html",params:{}}, } }, created(){ this.get_user_info(); this.change_avatar(); }, methods:{ get_user_info(){ var token = this.game.get("access_token") || this.game.fget("access_token"); // 獲取當前登陸用戶基本資訊 this.axios.post("",{ "jsonrpc": "2.0", "id": this.uuid(), "method": "User.info", "params": {} },{ headers:{ Authorization: "jwt " + token, } }).then(response=>{ var res = response.data.result; this.game.print(res); if(parseInt(res.errno) === 1000){ this.nickname = res.nickname; this.avatar = `${this.settings.avatar_url}?sign=${res.avatar}&token=${token}`; this.mobile = res.mobile; } }) }, change_avatar(){ api.addEventListener({ name: 'change_avatar' }, (ret, err)=>{ if( ret ){ var token = this.game.get("access_token") || this.game.fget("access_token"); this.avatar = `${this.settings.avatar_url}?sign=${ret.value.avatar}&token=${token}`; } }); }, goto_home(){ // this.game.outFrame("setting"); this.game.goFrame("user","user.html",this.current); }, change_account(){ // 切換帳號 this.game.goFrame("login","login.html", this.current); }, logout(){ // 退出帳號 api.actionSheet({ title: '您確認要退出當前登錄嗎?', cancelTitle: '取消', destructiveTitle: '退出登錄' }, (ret, err)=>{ if( ret ){ this.game.print(ret); // 取消為2 if(ret.buttonIndex==1){ this.game.save({"access_token":"","refresh_token":""}); this.game.fremove(["access_token","refresh_token"]); this.game.outWin("user"); } } }); }, update_avatar_frame(){ // 顯示修改頭像的頁面frame this.game.goFrame("avatar","avatar.html", this.current,null,{ type:"push", //動畫類型(詳見動畫類型常量) subType:"from_top", //動畫子類型(詳見動畫子類型常量) duration:300 //動畫過渡時間,默認300毫秒 }); }, update_transaction_password_frame(){ this.game.goFrame("transaction_password","transaction_password.html", this.current,null,{ type:"push", subType:"from_top", duration:300 }); }, update_password_frame(){ this.game.goFrame("password","password.html", this.current,null,{ type:"push", subType:"from_top", duration:300 }); }, update_nickname_frame(){ this.game.goFrame("password","password.html", this.current,null,{ type:"push", subType:"from_top", duration:300 }); } } }); } </script> </body> </html>
配置頁面點擊不同項進入不同頁面
2.交易頁面初始化
<!DOCTYPE html> <html> <head> <title>用戶中心</title> <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"> <meta charset="utf-8"> <link rel="stylesheet" href="../static/css/main.css"> <script src="../static/js/vue.js"></script> <script src="../static/js/axios.js"></script> <script src="../static/js/main.js"></script> <script src="../static/js/uuid.js"></script> <script src="../static/js/settings.js"></script> </head> <body> <div class="app frame avatar update_password" id="app"> <div class="box"> <p class="title">交易密碼</p> <img class="close" @click="close_frame" src="../static/images/close_btn1.png" alt=""> <div class="content"> <input class="password" type="text" v-model="password" placeholder="交易密碼...."> <input class="password password2" type="text" v-model="password2" placeholder="確認交易密碼...."> </div> <img @click="update_password_commit" class="btn" src="../static/images/yes.png" alt=""> </div> </div> <script> apiready = function(){ init(); new Vue({ el:"#app", data(){ return { password:"", password2:"", prev:{name:"",url:"",params:{}}, current:{name:"transaction_password",url:"transaction_password.html",params:{}}, } }, methods:{ close_frame(){ this.game.outFrame("transaction_password"); }, update_password_commit(){ // 提交用戶密碼 } } }); } </script> </body> </html>
交易頁面transaction_password.html初始化
交易介面CSS樣式
.update_nickname .nickname, .update_password .password { margin: 8rem 4.4rem 4rem; width: 19.50rem; height: 4rem; line-height: 4rem; background-color: #cc9966; outline: none; border: 1px solid #330000; text-align: center; font-size: 1.5rem; color: #ffffcc; } .update_password .password{ margin-top: 5.6rem; margin-bottom: 0.4rem; } .update_password .password2{ margin-top: 0.4rem; }
交易介面CSS樣式
3.密碼修改介面初始化
<!DOCTYPE html> <html> <head> <title>用戶中心</title> <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"> <meta charset="utf-8"> <link rel="stylesheet" href="../static/css/main.css"> <script src="../static/js/vue.js"></script> <script src="../static/js/axios.js"></script> <script src="../static/js/main.js"></script> <script src="../static/js/uuid.js"></script> <script src="../static/js/settings.js"></script> </head> <body> <div class="app frame avatar update_password" id="app"> <div class="box"> <p class="title">修改密碼</p> <img class="close" @click="close_frame" src="../static/images/close_btn1.png" alt=""> <div class="content"> <input class="password" type="text" v-model="password" placeholder="原密碼...."> <input class="password password2" type="text" v-model="password2" placeholder="新密碼...."> </div> <img @click="update_password_commit" class="btn" src="../static/images/yes.png" alt=""> </div> </div> <script> apiready = function(){ init(); new Vue({ el:"#app", data(){ return { password:"", password2:"", prev:{name:"",url:"",params:{}}, current:{name:"password",url:"password.html",params:{}}, } }, methods:{ close_frame(){ this.game.outFrame("password"); }, update_password_commit(){ // 提交用戶密碼 } } }); } </script> </body> </html>
密碼修改介面password.html
4.昵稱修改介面初始化
<!DOCTYPE html> <html> <head> <title>用戶中心</title> <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"> <meta charset="utf-8"> <link rel="stylesheet" href="../static/css/main.css"> <script src="../static/js/vue.js"></script> <script src="../static/js/axios.js"></script> <script src="../static/js/main.js"></script> <script src="../static/js/uuid.js"></script> <script src="../static/js/settings.js"></script> </head> <body> <div class="app frame avatar update_nickname" id="app"> <div class="box"> <p class="title">修改昵稱</p> <img class="close" @click="close_frame" src="../static/images/close_btn1.png" alt=""> <div class="content"> <input class="nickname" type="text" v-model="nickname" placeholder="輸入昵稱...."> </div> <img @click="update_nickname_commit" class="btn" src="../static/images/yes.png" alt=""> </div> </div> <script> apiready = function(){ init(); new Vue({ el:"#app", data(){ return { nickname:"", prev:{name:"",url:"",params:{}}, current:{name:"nickname",url:"nickname.html",params:{}}, } }, methods:{ close_frame(){ this.game.outFrame("nickname"); }, update_nickname_commit(){ // 提交用戶昵稱 } } }); } </script> </body> </html>
昵稱修改介面nickname.html初始化
5.交易密碼實現
1.模型中新增交易密碼欄位
from werkzeug.security import generate_password_hash, check_password_hash from application.utils.models import BaseModel,db class User(BaseModel): """用戶基本資訊""" # 新增一個交易密碼的欄位 _transaction_password = db.Column(db.String(255), comment="交易密碼") @property def transaction_password(self): return self._transaction_password @transaction_password.setter def transaction_password(self, rawpwd): """密碼加密""" self._transaction_password = generate_password_hash(rawpwd) def check_transaction_password(self, rawpwd): """驗證密碼""" return check_password_hash(self.transaction_password, rawpwd)
數據遷移,命令:
python manage.py db migrate -m "add user tansaction password" python manage.py db upgrade
@jsonrpc.method("User.transaction.password") @jwt_required # 驗證jwt def transaction_password(password1, password2,old_password=None): """ 交易密碼的初始化和修改 1. 剛註冊的用戶,沒有交易密碼,所以此處填寫的是新密碼 2. 已經有了交易密碼的用戶,修改舊的交易密碼 """ # 1.判斷兩次輸入密碼是否一致 if password1 != password2: return { "errno": status.CODE_TRANSACTION_PASSWORD_ERROR, "errmsg": message.transaction_password_not_match } # 2.判斷用戶是否存在 current_user_id = get_jwt_identity() user = User.query.get(current_user_id) if user is None: return { "errno": status.CODE_NO_USER, "errmsg": message.user_not_exists, } # 3.如果之前有存在交易密碼,則需要驗證舊密碼 if user.transaction_password: # 去資料庫查看用戶是否有舊的交易密碼 """修改""" # 驗證舊密碼 ret = user.check_transaction_password(old_password) if ret == False: # 如果驗證舊密碼失敗 return { "errno": status.CODE_PASSWORD_ERROR, "errmsg": message.transaction_password_error } """設置交易密碼""" user.transaction_password = password1 db.session.commit() return { "errno": status.CODE_OK, "errmsg": message.ok }
<!DOCTYPE html> <html> <head> <title>用戶中心</title> <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"> <meta charset="utf-8"> <link rel="stylesheet" href="../static/css/main.css"> <script src="../static/js/vue.js"></script> <script src="../static/js/axios.js"></script> <script src="../static/js/main.js"></script> <script src="../static/js/uuid.js"></script> <script src="../static/js/settings.js"></script> </head> <body> <div class="app frame avatar update_password" id="app"> <div class="box"> <p class="title">交易密碼</p> <img class="close" @click="close_frame" src="../static/images/close_btn1.png" alt=""> <div class="content" v-if="is_set_password"> <input class="password" type="password" v-model="old_password" placeholder="舊交易密碼...."> <input class="password password2" type="password" v-model="password1" placeholder="新交易密碼...."> <input class="password password2" type="password" v-model="password2" placeholder="確認新交易密碼...."> </div> <div class="content" v-else> <input class="password" type="password" v-model="password1" placeholder="交易密碼...."> <input class="password password2" type="password" v-model="password2" placeholder="確認交易密碼...."> </div> <img @click="update_password_commit" class="btn" src="../static/images/yes.png" alt=""> </div> </div> <script> apiready = function(){ init(); new Vue({ el:"#app", data(){ return { is_set_password: true, old_password: "", // 舊交易密碼 password1:"", // 新交易密碼 password2:"", // 確認新交易密碼 prev:{name:"",url:"",params:{}}, current:{name:"transaction_password",url:"transaction_password.html",params:{}}, } }, created(){ if( this.game.fget("is_set_transaction_password") === "false"){ this.is_set_password = false; } }, methods:{ close_frame(){ this.game.outFrame("transaction_password"); }, update_password_commit(){ // 1.提交用戶新密碼 params = { password1: this.password1, password2: this.password2, } // 2.如果不是第一次設置密碼,需要將舊密碼也提交到後端 if(this.is_set_password){ params.old_password = this.old_password; } // 3.向交易密碼後端介面發送請求 var token = this.game.get("access_token") || this.game.fget("access_token"); this.axios.post("",{ "jsonrpc": "2.0", "id": this.uuid(), "method": "User.transaction.password", "params": params },{ headers:{ Authorization: "jwt " + token, } }).then(response=>{ var res = response.data.result; if(parseInt(res.errno) === 1000){ this.game.fsave({"is_set_transaction_password":true}); this.game.outFrame("transaction_password"); }else{ api.alert({ title: '錯誤!', msg: res.errmsg, }, function(ret, err){ }); this.game.print(res.errno); } }).catch(error=>{ this.game.print(error); }); } } }); } </script> </body> </html>
@jsonrpc.method("User.transaction.password") @jwt_required # 驗證jwt def transaction_password(password1, password2,old_password=None): """ 交易密碼的初始化和修改 1. 剛註冊的用戶,沒有交易密碼,所以此處填寫的是新密碼 2. 已經有了交易密碼的用戶,修改舊的交易密碼 """ if password1 != password2: return { "errno": status.CODE_TRANSACTION_PASSWORD_ERROR, "errmsg": message.transaction_password_not_match } current_user_id = get_jwt_identity() user = User.query.get(current_user_id) if user is None: return { "errno": status.CODE_NO_USER, "errmsg": message.user_not_exists, } # 1.如果之前有存在交易密碼,則需要驗證舊密碼 if user.transaction_password: """修改""" # 驗證舊密碼 ret = user.check_transaction_password(old_password) if ret == False: return { "errno": status.CODE_PASSWORD_ERROR, "errmsg": message.transaction_password_error } """設置交易密碼""" user.transaction_password = password1 db.session.commit() # ***2.添加交易密碼的修改記錄,為了保證安全,僅僅記錄舊密碼!*** if old_password: document = { "user_id": user.id, "user_name": user.name, "user_nikcname": user.nickname, "updated_time": datetime.now().timestamp(), # 修改時間 "transaction_password": old_password, # 變更內容 "type": "transaction_password", # 本次操作的類型 } mongo.db.user_info_history.insert_one(document) return { "errno": status.CODE_OK, "errmsg": message.ok }