全栈开发一条龙——前端篇
第一篇:框架确定、ide设置与项目创建
第二篇:介绍项目文件意义、组件结构与导入以及setup的引入。
第三篇:setup语法,设置响应式数据。
第四篇:数据绑定、计算属性和watch监视
第五篇 : 组件间通信及知识补充
第六篇:生命周期和自定义hooks
第七篇:路由
第八篇:传参
第九篇:插槽,常用api和全局api。
全栈开发一条龙——全栈篇
第一篇:初识Flask&MySQL实现前后端通信
第二篇: sql操作、发送http请求和邮件发送
第三篇:全栈实现发送验证码注册账号
第四篇:图片验证码及知识补充
本章正式进入实战篇,来前后端分离制作一个问卷网站,有前后台和数据分析,最后项目上线。
文章目录
- 一、后端
- dataset_info
- data_set
- main
- token_ex
- login_blueprint
- 二、前端
- login.vue
- router
- app
- 三、效果展示
- 总结与预告
- 补充:内容加密/令牌token
- 与后端结合
- 与前端结合
第一步,我们实现login页面。
一、后端
我们创建一个social(后端内容都在里面)
dataset_info
我们首先将我们数据库的信息写入,建议还是要单独建立一个py文件,不然你后面项目上线,在服务器配置服务器还要专门去程序里面找东西改,太费劲了。
mysql_account = "root"
mysql_password = "xxx"
mysql_host = "localhost"
mysql_port = "3306"
mysql_data_col = "test_data"
需要加入的内容如上
data_set
接下来我们建立数据库对象,单独建立一个文件是因为我们可能在不同地方都要使用数据库,防止循环导入。
from flask_sqlalchemy import SQLAlchemy
import pymysql
pymysql.install_as_MySQLdb()
db = SQLAlchemy()
main
接下来我们制作我们的入口主程序,在这里,我们将我们的数据库连接上我们的flask服务程序,这样我们可以在后续的flask服务中操作,配置跨域,这样可以实现前后端全分离。最后,我们run一下服务。要打开服务,你在当前文件夹打开cmd,输入python main.py就好了。
from flask import Flask,jsonify,request
#jsonify将py数据转换为json数据,传给前端接口
from flask_cors import CORS
#跨域,因为有浏览器的同源策略,不同协议、域名、端口不能通信,我们要用cors来通信
from sqlalchemy import text
from flask.views import MethodView
#建立对象
app = Flask(__name__)
#转码,老外跟我们用的不一样,不改会乱码,如果有中文你要加上
app.config["JSON_AS_ASCII"] = False
from dataset_info import *
#导入数据库
from data_set import db
# 配置数据库
URI = "mysql://" + mysql_account + ":" + mysql_password + "@" + mysql_host + ":" + mysql_port + "/" + mysql_data_col
app.config["SQLALCHEMY_DATABASE_URI"] = URI
app.config["SQLALCHEMY_COMMIT_ON_TEARDOWN"] = True
#初始化操作
db.init_app(app)
#配置跨域,*表示所有人
CORS(app,cors_allowed_orgins = "*")
if __name__ == "__main__":
app.run(debug=True, host = "0.0.0.0",port = 5000)
token_ex
从这里开始,我们要开始正式写我们的登录逻辑了。我们输入一个账号和密码,然后后端验证,如果是有权限的,就生成一个token(登录凭证,这样在后续的内容中,就可以用令牌来证明身份来操作数据库等等)。于是我们需要先把生成令牌和解读令牌的逻辑写了。
import jwt
password = "1234"
class jwt_safe:
def __init__(self,data):
self.data = data
def encode(self):
try:
payload = jwt.encode( self.data , password , algorithm='HS256')
return payload
except jwt.DecodeError:
# 令牌解码失败
return 'Invalid token'
except jwt.ExpiredSignatureError:
# 令牌过期
return 'Expired token'
def decode(self):
try:
payload = jwt.decode( self.data, password , algorithms=['HS256'])
return payload
except jwt.DecodeError:
# 令牌解码失败
return 'Invalid token'
except jwt.ExpiredSignatureError:
# 令牌过期
return 'Expired token'
if __name__ == '__main__':
data = {'msg' : 123}
res = jwt_safe(data= data)
res = res.encode()
print(res)
res2 = jwt_safe(data = res)
res2 = res2.decode()
print(res2)
如上,我们设置一个密钥,然后根据这个密钥,我们制作一个可逆的加密,这样我们可以用encode来加密,然后用decode来解密验证。
login_blueprint
万事俱备,我们开始给我们的服务加上登录功能
from flask import Blueprint,jsonify,request
from flask.views import MethodView
from data_set import db
from token_ex import jwt_safe
login = Blueprint("login",__name__)
class login_(MethodView):
def get(self):
account = request.args.get("account",None)
password = request.args.get("password",None)
if not account or not password:
return jsonify( {"errcode":2,"msg":"缺失账号和密码"} )
if account == "123456" and password=="123456":
token_temp = {"account":account}
token = jwt_safe(token_temp)
res = token.encode()
return jsonify( {"errcode":0,"msg":"登录成功","token":res} )
return jsonify( {"errcode":1,"msg":"账号或密码错误"} )
pass
login.add_url_rule("/login/",view_func=login_.as_view("login") )
我们建立一个login对象,然后将类试图方法接在这个对象上。登录逻辑很简单,从前端用get方法获取账号和密码,如果账号密码正确,就生成一个令牌返回。
然后我们把这个蓝图在主服务程序中加入,
from login_blueprint import login
app.register_blueprint(login)
这样这个login就声明好了,我们可以通过访问host:5000/login/来访问
二、前端
我们后端写好了,再来写前端,前端需要一个界面,让我们输入账号密码,然后可以提交给后端验证。
login.vue
我们来写登录界面
<template>
<div class="register-box">
<h2>登录</h2>
<div class="form-group">
<label for="account">账号:</label>
<input type="text" id="account" v-model="account">
</div>
<div class="form-group">
<label for="password">密码:</label>
<input type="password" id="password" v-model="password">
</div>
<br>
<button @click="login">登录</button>
</div>
</template>
<script setup name="login">
import { ref } from 'vue';
const account = ref('');
const password = ref('');
import axios from 'axios';
import { routeLocationKey, useRouter } from 'vue-router';
const router = useRouter()
async function login() {
try{
let result=await axios.get('http://127.0.0.1:5000/login/',{params:{
account:account.value,
password:password.value
}})
window.alert(result.data.msg)
if(result.data.errcode == 0)
{
localStorage.setItem("token",result.data.token)
router.replace
setTimeout(()=>{router.push({path:"/home"})},2500)
}
}catch(error){alert(error)}
};
</script>
<style>
.register-box {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 300px;
height: 300px;
margin: auto;
padding: 20px;
border: 1px solid #ccc;
}
.form-group {
margin-bottom: 10px;
}
label {
font-weight: bold;
}
input[type="text"],
input[type="password"] {
width: 100%;
padding: 5px;
}
button {
width: 100%;
padding: 10px;
background-color: #007bff;
color: #fff;
border: none;
cursor: pointer;
}
button:hover {
background-color: #0069d9;
}
</style>
此段的逻辑很简单,绑定页面上的账号和密码变量,一旦用户点击登录,就向后端发送验证,如果验证通过,我们就将返回的令牌保存再本地,然后跳转到home页面。
router
我们还需要配置路由器,不然不能push切换新页面
import { createRouter } from "vue-router"
import home from "@/components/home.vue";
import login from "@/components/login.vue"
import { createWebHashHistory } from "vue-router";
const router = createRouter({
history:createWebHashHistory(),
//管理路由
routes:[ //一个一个的路由规则
{
name:'home',
//路径
path:'/home',
//组件绑定
component:home
},
{
path:'/login',
name : 'login',
component:login
},
{
path:'/',
redirect:'login'
}
]
})
export default router
我们在这里配置了login路由和home路由,同时将/这个初始的访问重定向到login页面。
app
最后,我们在app.vue中加入路由占位
<template>
<router-view></router-view>
</template>
<script setup name="app">
import login from '@/components/login.vue'
import { RouterView } from 'vue-router';
</script>
<style>
</style>
三、效果展示
这样我们就实现了最初的登录页面
总结与预告
本章我们创建了基础的工程,串联了前后端,制作了基础的登录页面,在之后,我们要先来制作管理员操作的后台。这之中,会用到flask Vue和mysql。
补充:内容加密/令牌token
加密
解密
我们不能让这个token永久有效,不然就可以让攻击者一直使用这个token
与后端结合
我们只在用户登录成功时生成token
与前端结合
我们前端拿到token之后,可以将它存放在本地存储里,这样在一段时间内,即使关掉会话或刷新,也可以继续维持登录状态
保存好之后我我们在其他地方访问:
localStorage.getItem("token")
如果访问到了,就会返回数值,不然返回null