vue-element-admin/template+tornado(pyrestful)前后端分离框架实践(2)——登录过程与后端python服务
本文较为详细的介绍vue-element-admin/template+tornado(pyrestful)前后端分离框架实践——登录过程与python后台API,分析vue-admin-admin登录过程。后端使用pyrestful插件(基于tornado)python实现,通过使用Fiddler与Postman工具分析,解决了跨域问题和json传参问题,详见代码。
花裤衩建议
你可以把 vue-element-admin当做工具箱或者集成方案仓库,在 vue-admin-template 的基础上进行二次开发,想要什么功能或者组件就去 vue-element-admin 那里复制过来。
vue-admin-template/src下的目录结构:
.
├── App.vue //入口
├── api // 各种接口
├── assets // 图片等资源
├── components // 各种公共组件,非公共组件在各自view下维护
├── icons //svg icon
├── main.js //入口
├── permission.js //认证入口
├── router // 路由表
├── store // 存储
├── styles // 各种样式
├── utils // 公共工具,非公共工具,在各自view下维护
└── views // 各种layout
git clone https://github.com/PanJiaChen/vue-admin-template
1. 登录前端
1.1. 登录过程源码解析
1.2. 登录配置
1.2.1. 修改Vue配置,替换mock
打开/vue.config.js文件,在devServer配置下,增加代理proxy内容,如下所示:
devServer: {
port: port,
open: true,
overlay: {
warnings: false,
errors: true
},
proxy: {
[process.env.VUE_APP_BASE_API]:{
target:'http://localhost:8090', //后期可以改
changeOrigin:true,
pathRewrite:{
['^' + process.env.VUE_APP_BASE_API]: ''
}
},
},
after: require('./mock/mock-server.js')
//before: require('./mock/mock-server.js')
},
1.2.2. 配置环境(env.development)后端代理
打开/.env.development文件
# just a flag
ENV = 'development'
# base api
# VUE_APP_BASE_API = '/dev-api' //替换后端地址
VUE_APP_BASE_API = 'http://localhost:8090/'
1.2.3. 与后端接口API
打开/src/api/user.js文件,可以使用原接口名称,也可以自定义。(本文使用原名称)
import request from '@/utils/request'
export function login(data) {
return request({
url: '/user/login',
method: 'post',
data
})
}
export function getInfo(token) {
return request({
url: '/user/info',
method: 'get',
params: { token }
})
}
1.3. 登录过程解析
本小节主要讲解登陆的流程以及我认为这个框架的厉害的东西:动态路由,之前看代码的时候,总想着一个登录搞那么麻烦,后面仔细品味发现原来一个小小的登录功能涉及到了这么多的东西。[6]
隆重推出/src/permission.js!
在登录过程中,permission.js是路由的全局钩子(beforeEach和afterEach),全局钩子的意思就是每次跳转的时候可以根据情况进行拦截,不让它进行跳转。主要使用场景就是有些页面需要用户登录之后才能访问,就可以在beforeEach中校验用户是否登陆来进行相对应的拦截处理。如代码所示。
router.beforeEach(async(to, from, next) => {
// start progress bar
NProgress.start()
// set page title
document.title = getPageTitle(to.meta.title)
// determine whether the user has logged in
const hasToken = getToken()
if (hasToken) {
if (to.path === '/login') {
// if is logged in, redirect to the home page
next({ path: '/' })
NProgress.done()
} else {
// determine whether the user has obtained his permission roles through getInfo
const hasRoles = store.getters.roles && store.getters.roles.length > 0
if (hasRoles) {
next()
} else {
try {
// get user info
// note: roles must be a object array! such as: ['admin'] or ,['developer','editor']
const { roles } = await store.dispatch('user/getInfo')
也就是说,登录过程由二维控制,普通过程是登录页(/src/views/login/index.vue)、输入用户名和密码(login)到后台python验证反馈code=20000和token、成功后路由(router)到主页;而另个permission过程是监控router动作,截取用户信息和token,如果已经登录但是没有用户信息,则调用getinfo(/src/api/user.js)接口。
[6]用一句话来概括:是否登陆?没有就给我老老实实登陆。是否有用户信息?没有就给我获取用户信息,并且生成可访问路由然后利用addRoutes进行添加。这两步都是actions:user/getInfo,permission/generateRoutes。
详见如下过程:
- 进入首页
首先判断是否有token,如果没有,则到登录页面(router指向过程:“next({ path: ‘/’ })”)。 - 登录页
/src/views/login/index.vue
点击登陆之后发生的第一个就是handleLogin方法。首先利用validate方法进行表单验证,再调用user/login方法,这个user/login是什么呢?一起来揭开它神秘的面纱。
handleLogin() {
this.$refs.loginForm.validate(valid => {
if (valid) {
this.loading = true
this.$store.dispatch('user/login', this.loginForm).then(() => {
this.$router.push({ path: this.redirect || '/' })
- user/login
/src/store/modules/user.js
简单的说就是登陆验证,登陆成功之后,分别保存token到vuex、cookie中。
// user login
login({ commit }, userInfo) {
const { username, password } = userInfo
return new Promise((resolve, reject) => {
login({ username: username.trim(), password: password }).then(response => {
const { data } = response
commit('SET_TOKEN', data.token)
setToken(data.token)
resolve()
2. 登录的后端
对于使用了Python的Tornado框架,设计发布为REST规范的webservice,.这里使用pyrestful的插件,pyRestful是一个API,用于使用Tornado Web服务器开发restful服务。
//这段代码是src/api/user.js中的代码,与后端接口的API
import request from '@/utils/request'
export function login(data) {
return request({
// 这里替换成自己的登陆接口,下面的也是一样
return request({
url: '/user/login',
method: 'post',
data
})
}
export function getInfo(token) {
return request({
url: '/user/info',
method: 'get',
params: { token }
})
}
2.1. 后端开发需要提前准备的
2.1.1. 跨域问题
Access to XMLHttpRequest at ‘http://localhost:8090/user/info?token=admin-token’ from origin ‘http://localhost:9528’ has been blocked by CORS policy: Request header field x-token is not allowed by Access-Control-Allow-Headers in preflight response.
由于API调用header中有token,需要为“Access-Control-Allow-Headers”增加“x-token”内容。通过Fiddler监控发现Vue的axios未构造、传递Http Header,需要自行设置,如下代码所示。
class UserResource(pyrestful.rest.RestHandler):
"""解决JS跨域请求问题"""
def set_default_headers(self):
self.set_header('Access-Control-Allow-Origin', '*')
self.set_header('Access-Control-Allow-Methods', 'POST, GET, OPTIONS')
self.set_header('Access-Control-Max-Age', 1000)
self.set_header('Content-type', 'application/json; charset=UTF-8')
self.set_header('Access-Control-Allow-Credentials', 'true')
self.set_header('Access-Control-Allow-Headers', 'Content-Type, x-token') # 后增加’ x-token‘
注:当然,可以使用Axios构造header,也能解决。不过本着依赖vue-element-admin原则,尽量不修改前端代码,特别是核心架构代码,则采用在后端由python来解决。
由于tornado及pyrestful未对“OPTIONS”做处理,需要自行接受OPTION信息,代码很简单,直接透明越过。
class UserResource(pyrestful.rest.RestHandler):
......
def options(self):
pass
2.1.2. rest API测试与监控
2.1.2.1 POSTMAN
使用Postman的Chrome插件,测试Rest API,效果如下:
2.1.2.2 Fiddler
Fiddler是最强大最好用的Web调试工具之一,它能记录所有客户端和服务器的http和https请求,允许你监视,设置断点,甚至修改输入输出数据。
通过Fiddler工具,监控输入request和返回response。
2.2. 源代码
由于这部分采用基于pyrestful插件实现,很多过程简化,为了快速演示整体架构技术实现,后台数据处理略过,直接返回需要的结果,达到技术实现的目标。
import tornado.ioloop
import pyrestful.rest
from pyrestful import mediatypes
from pyrestful.rest import get, post, put, delete
import os
os.environ['NLS_LANG'] = 'SIMPLIFIED CHINESE_CHINA.UTF8'
class User(object):
username = str
password = str
class UserResource(pyrestful.rest.RestHandler):
"""解决JS跨域请求问题"""
def set_default_headers(self):
self.set_header('Access-Control-Allow-Origin', '*')
self.set_header('Access-Control-Allow-Methods', 'POST, GET, OPTIONS')
self.set_header('Access-Control-Max-Age', 1000)
self.set_header('Content-type', 'application/json; charset=UTF-8')
self.set_header('Access-Control-Allow-Credentials', 'true')
self.set_header('Access-Control-Allow-Headers', 'Content-Type, x-token') # 后增加’ x-token‘
@get(_path="/user/info", _types=[str], _consumes=mediatypes.APPLICATION_JSON,_produces=mediatypes.APPLICATION_JSON)
def info(self, token):
print('start info!')
user = User()
user.username = token
print(token)
return {'code':20000,'data': {
'roles': ['admin'],
'introduction': 'I am a super administrator',
'avatar': 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
'name': 'Super Admin'
}}
@post("/user/login",{'format':'json'},_catch_fire=True)
def login(self,user):
userinfo = self.request.body
print(user)
return {"code":20000,"data":{"token":"admin-token"}}
def options(self):
pass
if __name__ == '__main__':
try:
print("Start the service")
app = pyrestful.rest.RestService([UserResource])
http_server = tornado.httpserver.HTTPServer(app)
#http_server.listen(8090,address='192.168.16.71')
http_server.listen(8090)
tornado.ioloop.IOLoop.instance().start()
except KeyboardInterrupt:
print("\nStop the service")
服务运行效果如下:
Start the service
b'{"username":"admin","password":"123456"}'
{'username': 'admin', 'password': '123456'}
start info!
通过短暂时间的分析与实践,vue-element-admin/template比较易用,外行短时间就能投入到业务实现中。
由于时间紧迫,先写到这样,欢迎反馈交流。
参考:
[1]《vue-element-admin登录流程》 CSDN博客 , 兔子零84 , 2019年09月
[2]《Vue 新手学习笔记:vue-element-admin 之登陆及目录权限控制》 CSDN博客 ,乐之终曲 ,2019年05月
[3]《Access-Control-Allow- 设置 跨域资源共享 CORS 详解》 CSDN博客 ,Normal Developer , 2017年12月
[4]《Cross-Origin Resource Sharing (CORS》) MDN web docs
[5]《使用vueAdmin开发后台管理系统(登录篇)》 CSDN博客 ,zw沐知 , 2020年7月
[6]《vue-element-admin 登陆详解》 艺宵博客 ,Vedu , 2020年08月
[7]《Nginx+Vue.js+Tornado前后端分离架构环境实践(3)》 CSDN博客 ,肖永威 ,2020年10月
[8]《Python基于Flask开发Restful API实践》 CSDN博客 ,肖永威 ,2018年7月
[9]《VUE中使用HTTP库Axios方法详解》 脚本之家 , 小火柴的蓝色理想 ,2020年2月
更多推荐
所有评论(0)