Flask Vue.js全栈开发|第4章:Vue.js调用API实现用户注册/登录/退出
Synopsis: 前端 Vue.js 如何划分组件,要动态显示 Alert 消息,父组件通过 props 给子组件传值即可。用户登录前后,导航栏上分别显示 Login 和 Logout 按钮,需要使用 store 模式维护一个共同的状态。另外,vue-router 的 beforeEach 可以指定哪些路由需要用户认证
代码已上传到 https://github.com/wangy8961/flask-vuejs-madblog/tree/v0.4 ,欢迎star
1. Vue-Router 导航
1.1 页面布局 Layout
前端的大致页面布局如下:
内容区域组件包含 Alert 子组件,原因是方便父组件通过 props
给子组件传值。导航栏组件共用,在 front-end/src/App.vue
中引入
创建 front-end/src/components/Navbar.vue
:
<template> <nav class="navbar navbar-expand-lg navbar-light bg-light" style="margin-bottom: 20px;"> <div class="container"> <router-link to="/" class="navbar-brand"> <img src="../assets/logo.png" width="30" height="30" class="d-inline-block align-top" alt=""> MadBlog </router-link> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarSupportedContent"> <ul class="navbar-nav mr-auto mt-2 mt-lg-0"> <li class="nav-item active"> <router-link to="/" class="nav-link">Home <span class="sr-only">(current)</span></router-link> </li> <li class="nav-item"> <a class="nav-link disabled" href="#">Explore</a> </li> </ul> <form class="form-inline navbar-left mr-auto"> <input class="form-control mr-sm-2" type="search" placeholder="Search"> <!-- 暂时先禁止提交,后续实现搜索再改回 type="submit" --> <button class="btn btn-outline-success my-2 my-sm-0" type="button">Search</button> </form> <ul class="nav navbar-nav navbar-right"> <li class="nav-item"> <a class="nav-link disabled" href="#">Messages</a> </li> <li class="nav-item"> <router-link to="/profile" class="nav-link">Profile</router-link> </li> <li class="nav-item"> <router-link to="/login" class="nav-link">Login</router-link> </li> </ul> </div> </div> </nav> </template> <script> export default { name: 'Navbar' //this is the name of the component } </script>
在导航栏组件中使用类似于
<router-link to="/login" class="nav-link">Login</router-link>
来导航到登录页面
修改 front-end/src/App.vue
:
<template> <div id="app"> <navbar></navbar> <router-view/> </div> </template> <script> import Navbar from './components/Navbar' export default { name: 'App', components: { navbar: Navbar } } </script> <style> </style>
浏览器 http://localhost:8080/#/
将看到之前的 Pong!
按钮
1.2 Alert 组件
创建子组件 front-end/src/components/Alert.vue
:
<template> <div class="alert" role="alert" v-bind:class="'alert-' + variant"> {{ message }} </div> </template> <script> export default { props: ['variant', 'message'] } </script>
子组件 Alert.vue 可以接收父组件传递的 variant
和 message
数据,下面演示父组件如何动态传递数据给 Alert.vue
创建父组件 front-end/src/components/Home.vue
:
<template> <div class="container"> <alert v-for="(alert, index) in alerts" :key="index" v-if="alert.showAlert" v-bind:variant="alert.alertVariant" v-bind:message="alert.alertMessage"> </alert> <button type="button" class="btn btn-primary">HomePage</button> </div> </template> <script> import Alert from './Alert' export default { name: 'Home', //this is the name of the component components: { alert: Alert }, data () { return { alerts: [ { showAlert: true, alertVariant: 'danger', alertMessage: 0 }, { showAlert: true, alertVariant: 'info', alertMessage: 1 }, { showAlert: true, alertVariant: 'dark', alertMessage: 2 } ] } } } </script>
在 front-end/src/components/
目录下分别创建 Login.vue
, Register.vue
, Profile.vue
,代码在 https://github.com/wangy8961/flask-vuejs-madblog/tree/v0.4
1.3 导航守卫 beforeEach
只有用户登录后才能访问 Home、Profile 等,需要使用 Vue-Router
的 router.beforeEach()
在每次路由前判断是否需要用户验证,关于 "导航守卫" 功能请阅读官方文档 https://router.vuejs.org/zh/guide/advanced/navigation-guards.html
修改 front-end/src/router/index.js
:
import Vue from 'vue' import Router from 'vue-router' import Home from '@/components/Home' import Login from '@/components/Login' import Register from '@/components/Register' import Profile from '@/components/Profile' import Ping from '@/components/Ping' Vue.use(Router) const router = new Router({ routes: [ { path: '/', name: 'Home', component: Home, meta: { requiresAuth: true } }, { path: '/login', name: 'Login', component: Login }, { path: '/register', name: 'Register', component: Register }, { path: '/profile', name: 'Profile', component: Profile, meta: { requiresAuth: true } }, { path: '/ping', name: 'Ping', component: Ping } ] }) router.beforeEach((to, from, next) => { const token = window.localStorage.getItem('token') if (to.matched.some(record => record.meta.requiresAuth) && (!token || token === null)) { next({ path: '/login', query: { redirect: to.fullPath } }) } else if (token && to.name == 'Login') { // 用户已登录,但又去访问登录页面时不让他过去 next({ path: from.fullPath }) } else { next() } }) export default router
现在客户端如果要访问 http://localhost:8080/#/
,会被重定向到 http://localhost:8080/#/login?redirect=%2F
需要先登录验证才行
2. 用户注册
Register.vue
组件代码如下:
17 条评论
评论者的用户名
评论时间henrybill30
2019-11-21T15:20:33Z您好,我是刚开始学习的小白,请问前端代码中用户登录的时候是通过什么验证用户名密码是否正确的,是token吗,但‘api/token’这个url不是login_required的吗?
Madman henrybill30 Author
2019-11-22T02:13:00Z前端通过 Basic Auth 认证,提供用户名和密码,请求后端
http://localhost:5000/api/tokens
,如果用户名密码正确则发放有效 Token:henrybill30 Madman
2019-11-22T03:15:16Z好的,我尝试一下,谢谢!
皓月qhy
2019-11-27T09:52:01Z代码有个小bug 在登录成功后,这里会存储一个madblog-token,但是在导航守卫时使用的是token,所以会导致导航守卫失效 window.localStorage.setItem('madblog-token', response.data.token) const token = window.localStorage.getItem('token')
mingkai 皓月qhy
2020-08-11T03:22:56Z多谢大神指出。 我说刚开始怎么点home 以后出现登录页面,登录以后点home ,还是要登录。
把const token = window.localStorage.getItem('token') 改成 const token = window.localStorage.getItem('madblog-token') 就可以了
vow
2020-02-07T11:56:37Z1.2小节当中的
v-for和v-if是不是不能同时出现呢?
mingkai vow
2020-08-05T06:29:50Z我也遇到这个问题。 错误提示:
5:7 error The 'alerts' variable inside 'v-for' directive should be replaced with a computed property that returns filtered array instead. You should not mix 'v-for' with 'v-if' vue/no-use-v-if-with-v-for
mingkai mingkai
2020-08-11T03:26:00Z改成compute 方法就ok了。
六六六意啊
2020-04-08T13:24:36Z请问您用户的登录注册尝试过中文填写吗,按照您的源码来,注册中文是可以的,也可以添加进数据库,但是对于登录而言,如果是英文字母是可以前端给后端发token请求的,但是中文请求却发不过去,报错为 Cannot read property 'status' of undefined。希望可以得到解答,谢谢!
Madman 六六六意啊 Author
2020-04-08T14:17:23Z使用 Flask-HTTPAuth 验证用户名、密码(app/api/auth.py):
如果你用 postman 测试,传入中文字符的 username 时,verify_password() 函数获取的 username 字符乱码了,所以找不到用户! 你可以不用 Flask-HTTPAuth,换其他模块
moelee
2020-08-02T18:34:53Z到“1.3 导航守卫 beforeEach ” 这步时报错,我应该怎么处理呢?
imobs
2021-06-22T12:11:27Z登录页面 报错要怎么处理?Uncaught (in promise) Error: Redirected when going from "/login" to "/" via a navigation guard.
Madman imobs Author
2021-06-22T12:22:02Z使用package.json中vue-router相同版本号
imobs Madman
2021-06-22T12:24:55Z和你仓库的是一个版本"vue-router": "^3.0.1"
Madman imobs Author
2021-06-22T12:35:39Zhttps://blog.csdn.net/weixin_44039043/article/details/109400572 参考下
imobs Madman
2021-06-22T12:54:45Z解决了,谢谢!另外说一下,评论好像上传不了图片
Madman imobs Author
2021-06-22T13:01:56Z是的,目前只能使用图片链接,因为用的人少😁