VUE+Flask登录的初探--前端(Vue+element+axios)+后端(Flask+FlaskLogin+JWT)

摘要:
(这是一种编码方法。安装组件是一种破坏性的行为,需要认真测试以避免以后跪下。)importVuefrom'vu'importAppfrom'/App。vu'importElementUIfrom'element-uiimport'element-ui/lib/theme粉笔/index。cs'importAxiosfrom'axios'importVueAxiosfrom'vue-axios'//vue。配置。productionTip=假eaxios。默认值。其中凭据=trueVue。使用Vue。使用newVue$mountViewCode4.在components目录下创建Login.vue文件{titleMsg}}提交重置导出默认值{name:'loginForm',data(){return{titleMsg:'欢迎来到标志世界',loginData:{用户名:'',密码:''}}}},方法:{submitForm{this.$refs[formName].validate((valid)=˃{if(有效){console.log('submit')}else{console.log('llegadsubmit!!');returnfalse;})},ResetForm{this.$refs[formName].resetFields()console.log}}ViewCode5。打开App.vue,注释helloworld的相关代码并用Login覆盖它。这一操作可以加深对vue组成机制的理解。为以后学习使用路由器奠定基础˂----˃//importHelloWorldfrom'。/组件/HelloWorld。vu'importLoginfrom'/组件/登录。vueexportdefault{name:“App”,组件:{//HelloWorldLogin}}#App{font-family:Avenir,Helvetica,Arial,sans-serif;-webkit字体移动:抗锯齿;-moz os x字体移动:灰度;文本对齐:居中;颜色:#2c3e50;页边空白:60 px;}ViewCode6.npmrunserve运行如下所示。首先,转到py端并实现部分后端代码。

0.前端部分依然基于VueCLI (https://cli.vuejs.org/zh/

1.创建hello-login文件夹,然后再此文件夹内执行 vue create front-end ,一顿狂回车后,如下图所示:

VUE+Flask登录的初探--前端(Vue+element+axios)+后端(Flask+FlaskLogin+JWT)第1张

 2.安装elementUI,axios,js-cookie,qs
  2.1  npm i element-ui -S  (https://element.eleme.cn/#/zh-CN/component/installation
  2.2  npm install --save axios vue-axios  (http://www.axios-js.com/zh-cn/docs/vue-axios.html)
  2.3  npm install js-cookie --save (https://www.npmjs.com/package/js-cookie)
  2.4  npm install qs --save (https://www.npmjs.com/package/qs)

3.打开main.js,把elementUI和axios加载。搞定这块代码,npm run serve,试试能否正常把项目跑起来。(这是一种编码方式,安装组件算是破坏性的动作,需要勤于测试。以免后期跪了)

VUE+Flask登录的初探--前端(Vue+element+axios)+后端(Flask+FlaskLogin+JWT)第2张VUE+Flask登录的初探--前端(Vue+element+axios)+后端(Flask+FlaskLogin+JWT)第3张
import Vue from 'vue'
import App from './App.vue'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import axios from 'axios'
import VueAxios from 'vue-axios'

//Vue.config.productionTip = false
axios.defaults.withCredentials = true

Vue.use(VueAxios,axios)
Vue.use(ElementUI)

new Vue({
  render: h => h(App),
}).$mount('#app')
View Code

4.在components目录下 创建Login.vue文件

VUE+Flask登录的初探--前端(Vue+element+axios)+后端(Flask+FlaskLogin+JWT)第4张VUE+Flask登录的初探--前端(Vue+element+axios)+后端(Flask+FlaskLogin+JWT)第5张
<template>
  <div class='login'>
    <h1>{{ titleMsg }}</h1>
    <el-form ref="loginForm" :model="loginData" label-width="100px">
      <el-form-item label="用户名" prop="username" :rules="[{required: true, message: '用户名不能为空'}]">
        <el-input ref="username" type="password" v-model="loginData.username" autocomplete="off"></el-input>
      </el-form-item>
      <el-form-item label="密码" prop="password" :rules="[{required: true, message: '密码不能为空'}]">
        <el-input type="password" v-model="loginData.password" autocomplete="off"></el-input>
      </el-form-item>      
      <el-form-item>
        <el-button type="primary" @click="submitForm('loginForm')">提交</el-button>
        <el-button @click="resetForm('loginForm')">重置</el-button>
      </el-form-item>
    </el-form>
  </div>
</template>

<script>
export default {
  name: 'loginForm',
  data() {
    return {
      titleMsg: '欢迎来到旗帜世界',
      loginData: {
        username: '',
        password: ''
      }
    }
  },
  methods: {
    submitForm(formName) {
      this.$refs[formName].validate((valid) => {
         if (valid) {
           console.log('submit')
         } else {
          console.log('illegad submit!!');
          return false;
        }
      })
    },
    resetForm(formName) {
      this.$refs[formName].resetFields()
      console.log('reset')
    }
  }
}
</script>
View Code

5.打开App.vue,将helloworld相关代码注释,改写成Login。这种操作可以加深理解vue的组件机制。为后期学习使用router打基础

VUE+Flask登录的初探--前端(Vue+element+axios)+后端(Flask+FlaskLogin+JWT)第6张VUE+Flask登录的初探--前端(Vue+element+axios)+后端(Flask+FlaskLogin+JWT)第7张
<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png">
    <!-- <HelloWorld msg="Welcome to Your Vue.js App"/> -->
    <Login/>
  </div>
</template>

<script>
// import HelloWorld from './components/HelloWorld.vue'
import Login from './components/Login.vue'

export default {
  name: 'App',
  components: {
    //HelloWorld
    Login
  }
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>
View Code

6.npm run serve 跑起来后如下图。
VUE+Flask登录的初探--前端(Vue+element+axios)+后端(Flask+FlaskLogin+JWT)第8张

7.接下来,使用axios把此表单提交到py搭建的后台并返回消息。先转到py端,把后端代码实现一部分。在完成这个功能吧。

--------------------------------------------------------------------------------------------------------------------------------------------------------------

0.后端实现,使用flask(https://dormousehole.readthedocs.io/en/latest/

1.在hello-login文件夹下创建 back-end文件夹,并运行命令行 py -m venv venv  这时就会在当前目录下创建venv虚拟机 (https://dormousehole.readthedocs.io/en/latest/installation.html#id4

2.执行venvscriptsactivate 这样就启动了虚拟机环境 
VUE+Flask登录的初探--前端(Vue+element+axios)+后端(Flask+FlaskLogin+JWT)第9张

3.开始安装flask, flask-login, flask-cors, jwt 。注意都要在venv虚拟机环境下安装
  3.1 pip install Flask (https://dormousehole.readthedocs.io/en/latest/installation.html#flask
  3.2 pip install flask-login  (https://flask-login.readthedocs.io/en/latest/)
  3.3 pip install pyjwt  (https://pypi.org/project/PyJWT/)
  3.4 pip install -U flask-cors  (https://flask-cors.readthedocs.io/en/latest/)

4.在当前目录下创建app.py文件 敲入代码:

VUE+Flask登录的初探--前端(Vue+element+axios)+后端(Flask+FlaskLogin+JWT)第10张VUE+Flask登录的初探--前端(Vue+element+axios)+后端(Flask+FlaskLogin+JWT)第11张
from flask import Flask
import json

app = Flask(__name__)
app.secret_key =b'x15fx07xd3xd9xbf*x82xd1xe6xb4xf2x95xddx8fx12'
#命令行中运行后拷贝出随机值  python -c "import os; print(os.urandom(16))"

@app.route('/hello')
def helloworld():
  returnData = {'code': 0, 'msg': 'success', 'data': 'hello world' }
  return json.dumps(returnData),200

if __name__ == '__main__':
  app.run(debug = True)
View Code

5.在venv虚拟机下 运行py app.py 然后再浏览器中查看 http://localhost:5000/hello  。这说明基本框架已经构建成功。
之所以返回如下格式,是参考了这篇博文(https://sobird.me/http-json-api-guide.htm),原始出处并未找到,
VUE+Flask登录的初探--前端(Vue+element+axios)+后端(Flask+FlaskLogin+JWT)第12张

6.创建用户单元.user.py。实现了flask_login (https://flask-login.readthedocs.io/en/latest/index.html#your-user-class)所提及的功能。以及用USERS字典暂时代替未来的数据库表。

VUE+Flask登录的初探--前端(Vue+element+axios)+后端(Flask+FlaskLogin+JWT)第13张VUE+Flask登录的初探--前端(Vue+element+axios)+后端(Flask+FlaskLogin+JWT)第14张
from flask_login import UserMixin
from werkzeug.security import check_password_hash,generate_password_hash


USERS = [
    {
        "id":1,
        "name":"admin",
        "password":generate_password_hash('123')
    },
    {
        "id":2,
        "name":"李四",
        "password":generate_password_hash('123')
    },    
]


 
class User(UserMixin):
    def __init__(self,user):
        self.username = user.get("name")
        self.password_hash = user.get("password")
        self.id = user.get("id")


    @staticmethod
    def queryUser(username):
        for user in USERS:
            if (user.get('name') == username) :
                return User(user)
        return None
    
    def verifyPassword(self,password):
        if self.password_hash is None:
            return False
        return check_password_hash(self.password_hash,password)

    def get_id(self):
        return self.id

    def get(user_id):
        if not user_id:
            return None
        for user in USERS:
            if str(user.get('id')) == str(user_id) :
                return User(user)
        print('None')
        return None
View Code

7.创建jwt操作单元jwt_token.py 。实现了对jwt的简单二次封装。其实不做封装也可以
  7.1 JWT中 “Registered claims” 包含 iss(发行者),exp(到期时间),sub(主题),aud(受众)是官方建议携带的。我偷懒只采用了到期时间这一个声明。
  7.2 jwt可以参考官网(https://jwt.io/)介于国内强大的长城。此官网偶发型能打开。   亦可参考此博文 https://www.cnblogs.com/mantoudev/p/8994341.html

VUE+Flask登录的初探--前端(Vue+element+axios)+后端(Flask+FlaskLogin+JWT)第15张VUE+Flask登录的初探--前端(Vue+element+axios)+后端(Flask+FlaskLogin+JWT)第16张
from jwt import jwt,PyJWTError
from datetime import datetime,timedelta

SECRECT_KEY = b'x92R!x8exc6x9cxb3x89#xa6x0cxcbxf6xcbxd7xbc'


def genToken(data):
  expInt = datetime.utcnow() + timedelta(seconds=3)
  payload = {
    'exp': expInt,
    'data': data 
    }
  token = jwt.encode(payload,key= SECRECT_KEY,algorithm= 'HS256')
  return bytes.decode(token)

def verfiyToken(tokenStr):
  try:
    tokenBytes =  tokenStr.encode('utf-8')
    payload = jwt.decode(tokenBytes,key= SECRECT_KEY,algorithm= 'HS256')
    return payload
  except PyJWTError as e:
    print("jwt验证失败: %s" % e)
    return None
View Code

8.创建登录逻辑单元 login.py 。同前端的主要交互逻辑都在此处。flask_login的具体实现(https://flask-login.readthedocs.io/en/latest/index.html#installation)

VUE+Flask登录的初探--前端(Vue+element+axios)+后端(Flask+FlaskLogin+JWT)第17张VUE+Flask登录的初探--前端(Vue+element+axios)+后端(Flask+FlaskLogin+JWT)第18张
import time
import json
from flask import Blueprint,request
from flask_login import LoginManager,login_user,logout_user,login_required,current_user
from user import User,USERS
from jwt_token import genToken,verfiyToken

login_page = Blueprint('login_page',__name__)

login_manager = LoginManager()
login_manager.login_view = 'helloworld'

@login_page.record_once
def on_load(state):
  login_manager.init_app(state.app)

# @login_manager.user_loader
# def load_user(user_id):
#   return User.get(user_id)

@login_manager.request_loader
def load_user_from_request(request):
  token = request.headers.get('Authorization')
  if token == None:
    return None

  payload = verfiyToken(token)
  if payload != None:
    user = User.queryUser(payload['data']['username'])
  else:
    user = None
  return user


@login_page.route('/first')
@login_required
def firstPage():
  returnData = {'code': 0, 'msg': 'success', 'data': 'First Blood(来自' + current_user.username +')' }
  return returnData,200

@login_page.route('/login', methods=['POST'])
def login():
  if request.method == 'POST':
    username = request.form['username']
    password = request.form['password']
    user = User.queryUser(username)
    if (user != None) and (user.verifyPassword(password)) :
      login_user(user)
      token = genToken({'username':username,'password':'******'})
      returnData = {'code': 0, 'msg': 'success', 'data': {'token':token} }
      return json.dumps(returnData),200
    else :
      returnData = {'code': 1, 'msg': 'success', 'data': 'username or password is not correct' }
      return json.dumps(returnData),200  

@login_page.route('/logout') 
@login_required
def logout():
  username = current_user.username
  logout_user()
  returnData = {'code': 0, 'msg': 'success', 'data': ' Bye ' + username }
  return json.dumps(returnData),200  
View Code

9.执行py app.py 后,在postman 分别测试如下链接(注意图中红框内容。):
  9.1 http://127.0.0.1:5000/hello
  9.2 http://127.0.0.1:5000/login
  9.3 http://127.0.0.1:5000/first
  9.4 http://127.0.0.1:5000/logout 
VUE+Flask登录的初探--前端(Vue+element+axios)+后端(Flask+FlaskLogin+JWT)第19张

VUE+Flask登录的初探--前端(Vue+element+axios)+后端(Flask+FlaskLogin+JWT)第20张

 VUE+Flask登录的初探--前端(Vue+element+axios)+后端(Flask+FlaskLogin+JWT)第21张

 VUE+Flask登录的初探--前端(Vue+element+axios)+后端(Flask+FlaskLogin+JWT)第22张

 10.后端代码初步结束。下一阶段,连接前后端

--------------------------------------------------------------------------------------------------------------------------------------------------

1.打开front-end项目,用axios把后端接口调用起来
2.在项目src目录下 创建文件夹 utils 然后在其内创建文件request.js。这里对axios做了简单封装。

VUE+Flask登录的初探--前端(Vue+element+axios)+后端(Flask+FlaskLogin+JWT)第23张VUE+Flask登录的初探--前端(Vue+element+axios)+后端(Flask+FlaskLogin+JWT)第24张
import axios from 'axios'
import Cookies from 'js-cookie'


/****** 创建axios实例 ******/
const service = axios.create({
  baseURL: 'http://localhost:5000',  // api的base_url
  timeout: 5000  // 请求超时时间
})

service.interceptors.request.use(
  config => {
    config.headers['Authorization'] = Cookies.get('Authorization')
    return config
  },
  error => {
    console.log(error)
    return Promise.reject(error)
  }
)

/****** respone拦截器==>对响应做处理 ******/
// service.interceptors.response.use(
//   response => {
//     console.log(response)
//     //这里根据后端提供的数据进行对应的处理
//     if (response.data.result === 'TRUE') {
//         return response.data;
//     }
//   },
//   error => {
//     console.log(error);
//     return Promise.reject(error)
//   }
// )

export default service;
request.js
VUE+Flask登录的初探--前端(Vue+element+axios)+后端(Flask+FlaskLogin+JWT)第25张VUE+Flask登录的初探--前端(Vue+element+axios)+后端(Flask+FlaskLogin+JWT)第26张
<template>
  <div class='login'>
    <h1>{{ titleMsg }}</h1>
    <el-form ref="loginForm" :model="loginData" label-width="100px">
      <el-form-item label="用户名" prop="username" :rules="[{required: true, message: '用户名不能为空'}]">
        <el-input ref="username" type="password" v-model="loginData.username" autocomplete="off"></el-input>
      </el-form-item>
      <el-form-item label="密码" prop="password" :rules="[{required: true, message: '密码不能为空'}]">
        <el-input type="password" v-model="loginData.password" autocomplete="off"></el-input>
      </el-form-item>      
      <el-form-item>
        <el-button type="primary" @click="loginForm('loginForm')">提交</el-button>
        <el-button @click="resetForm('loginForm')">重置</el-button>
      </el-form-item>
      <el-form-item>
        <el-button @click="testForm()">测试</el-button>
        <el-button @click="logoutForm()">登出</el-button>
      </el-form-item>
    </el-form>
  </div>
</template>

<script>
import qs from 'qs'
import service from '../utils/request'
import Cookies from 'js-cookie'
export default {
  name: 'loginForm',
  data() {
    return {
      titleMsg: '欢迎来到旗帜世界',
      loginData: {
        username: '',
        password: ''
      }
    }
  },
  methods: {
    loginForm(formName) {
      this.$refs[formName].validate((valid) => {
         if (valid) {
           service({url: '/login',method: 'post',data: qs.stringify(this.loginData)})
             .then(response => {
               const { data } = response
               Cookies.set('Authorization',data.data.token)
               alert('submit!!!' +'
'+ data.msg)
             })
             .catch(error => {
               console.log(error)
             })
         } else {
           console.log('illegad submit!!');
           return false;
        }
      })
    },
    testForm() {
      service({url: '/first',method: 'get'})
        .then(response => {
          const { data } = response
          alert('firstPage!!!' +'
'+ data.data)
        })
        .catch(error => {
          console.log(error)
        })
    },
    logoutForm() {
      service({url: '/logout',method: 'get'})
        .then(response => {
          const { data } = response
          alert('logout!!!' +'
'+ data.data)
        })
        .catch(error => {
          console.log(error)
        })
    }
  }
}
</script>
Login.vue

3.npm run serve 后,测试。四个按钮
VUE+Flask登录的初探--前端(Vue+element+axios)+后端(Flask+FlaskLogin+JWT)第27张

 4.其中关注一个状况,当登出后,再次点击测试。测试依然返回成功。这就出现一个问题,登出功能无效,回看后端代码logout是正常运作。
稍加分析,即可得出产生这种情况的原因是jwt Token本身的弊端。前文的连接中已经提醒。如何解决此状况,日后再分析

5.收工了。

免责声明:文章转载自《VUE+Flask登录的初探--前端(Vue+element+axios)+后端(Flask+FlaskLogin+JWT)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇【转载】C#中使用double.Parse方法将字符串转换为双精度double类型递归实现阶乘下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

一篇文章教会你用Python抓取抖音app热点数据

今天给大家分享一篇简单的安卓app数据分析及抓取方法。以抖音为例,我们想要抓取抖音的热点榜数据。 要知道,这个数据是没有网页版的,只能从手机端下手。 首先我们要安装charles抓包APP数据,它是一款收费的抓包修改工具,易上手,数据请求容易控制,修改简单,抓取数据的开始暂停方便等优势,网上也有汉化版,下载地址为http://www.zdfans.com/...

(appium+python)UI自动化_02_appium启动手机app

前提:需先安装配置好appium+python自动化环境,已配置好环境的小伙伴可以参考以下步骤启动Android app,具体步骤如下: 一、USB连接手机 (1)手机USB连接电脑 (2)手机打开开发者模式、USB调试功能 二、基础信息配置 1,获取设备号 终端获取设备号,指令:adb devices   2,获取apk包名、activity (1)打开...

ios 获取app版本号

let infoDictionary = Bundle.main.infoDictionary!let appversion = infoDictionary["CFBundleShortVersionString"] as! String   //获取app的版本号 let deviceId = UIDevice.current.identifierFo...

一起谈.NET技术,ASP.NET MVC3 基础教程 – Web Pages 1.0 狼人:

  I:Web Pages 1.0中以“_”开头的特别文件(文件命名时不区分大小写)   “_appstart.cshtml” & “_pagestart.cshtml” & “_viewstart.cshtml”   _appstart.cshtml - 应用程序启动时在Global. Application_Start方法后执行。  ...

二、vue响应式对象

Object.defineProperty Object.defineProperty 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象,先来看一下它的语法: Object.defineProperty(obj, prop, descriptor) obj 是要在其上定义属性的对象; prop 是要定义或修改的属性的...

第二节:Vue3向下兼容1(Mustcache v-once text html pre cloak v-bind v-on v-if v-show等等)

一. 常用指令1 1. Mustache语法(双大括号)  如果我们希望把数据显示到模板(template)中,使用最多的语法是 “Mustache”语法 (双大括号)的文本插值。并且我们知道,data返回的对象是有添加到Vue的响应式系统中;  当data中的数据发生改变时,对应的内容也会发生更新。当然,Mustache中不仅仅可以是data中的属性,也...