我是一名前端开发,我为自己带盐。【满纸荒唐言,一把辛酸泪。都云作者痴,谁解其中味?】
下载地址:链接: https://pan.baidu.com/s/13FRqPlM7_qSbUizjIh8UjQ 提取码: ipk4
上一篇已写到基本的数据库创建(本地数据库test,并创建admin表),后端接口userList 查用用户,vue前端搭建以及获取接口,具体可以到从零开始搭建一个网站后台管理系统(node+vue+SQL)(1) 查看。
思路
1:数据库表admin,包含字段(默认 Id, userId ,userName, password ,token)
2:node项目里面app.js创建接口,token生成需要下载一个jsonwebtoken插件
3:vue项目下载一个element-ui 包
实现后效果
ready , go~
1:第一步,数据库
DROP TABLE IF EXISTS `admin`; CREATE TABLE `admin` ( `Id` int(11) NOT NULL AUTO_INCREMENT, `userId` varchar(255) DEFAULT NULL, `userName` varchar(255) DEFAULT NULL, `password` varchar(255) DEFAULT NULL, `token` varchar(255) DEFAULT NULL, PRIMARY KEY (`Id`) ) ENGINE=MyISAM AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;2:第二步,node 项目中app.js
var express = require('express'); var path = require('path'); var app = express(); var bodyParser = require('body-parser'); var mysql = require('mysql'); var fs = require("fs"); var jwt = require("jsonwebtoken"); //npm install mysql 安装mysql var db = require('./config/db.js'); app.all("*", function (req, res, next) { //设置允许跨域的域名,*代表允许任意域名跨域 res.header("Access-Control-Allow-Origin", "*"); //允许的header类型 res.header("Access-Control-Allow-Headers", "content-type"); //跨域允许的请求方式 res.header("Access-Control-Allow-Methods", "DELETE,PUT,POST,GET,OPTIONS"); if (req.method.toLowerCase() == 'options') res.send(200); //让options尝试请求快速结束 else next(); }) // 登录管理员 app.get('/loginUser', function (req, res) { // console.log(req) db.query('SELECT * FROM admin WHERE username ="' + req.query.username + '" AND password="' + req.query.password+ '"', null, function (err, docs) { if (err) { console.log(err); return; } if (docs.length > 0) { let content = { uname: req.query.username }; // 要生成token的主题信息 let secretOrPrivateKey = "suiyi" // 这是加密的key(密钥) let token = jwt.sign(content, secretOrPrivateKey, { expiresIn: 60 * 60 * 24 // 24小时过期 }); //token写入数据库docs[0].token = token db.query('UPDATE admin SET token="' + token + '" WHERE username ="' + req.query.username + '"', null, function (err, result) { if (err) { console.log(err); return; } res.send({ msg: '登录成功,返回token~', code: 200, data: result, token: token }); }); } else { res.send({ msg: '登录失败~', code: 0, data: docs }); } }); }); // 注册管理员 app.get('/registerUser', function (req, res) { // console.log(req.query); db.query('INSERT INTO admin (Id,username ,password) VALUES(' + req.query.Id + ',"' + req.query.username + '","' + req.query.password+ '")', null, function (err, docs) { if (err) { console.log(err); return; } if (docs) { let content = { uname: req.query.username }; // 要生成token的主题信息 let secretOrPrivateKey = "suiyi" // 这是加密的key(密钥) let token = jwt.sign(content, secretOrPrivateKey, { expiresIn: 60 * 60 * 24 // 24小时过期 }); //token写入数据库docs[0].token = token db.query('UPDATE admin SET token="' + token + '" WHERE username="' + req.query.username+ '"', null, function (err, result) { if (err) { console.log(err); return; } res.send({ msg: '注册成功~', code: 200, data: result, token: token }); }); } else { res.send({ msg: '注册失败~', code: 0, data: docs }); return; } }); }); // 退出登录 ,重置 用户token app.get('/loginOut', function (req, res) { db.query('UPDATE admin SET token="" WHERE uid ="' + req.query.uid +'"', null, function (err, result) { if (err) { console.log(err); return; } res.send({ msg: '退出成功~', code: 200, data: result }); }); }); var server = app.listen(800, function () { console.log("run......"); });下面着重说明几点,开发过程中遇到的问题
1:前后端交互,node是怎么获取前端传递过来的参数的?(get方法)获取/admin?username =zhangsan这样的参数
答:首先的了解Node.js Express 里常常见到function(req, res, next), 这3个参数分别是什么意思。
req : request的缩写, 请求的数据(前端发起的请求,包含了查询字符串,参数,内容,HTTP 头部等属性)
// 登录管理员 app.get('/loginUser', function (req, res) { // param 相当于前端发起接口请求的参数 // var param ={ // username : '', // password: '' // }, //那么req.query 就相当 param这个参数 ,所以下面调用也是通过 req.query.username 获取前端参数的 db.query('SELECT * FROM admin WHERE username ="' + req.query.username + '" AND password="' + req.query.password+ '"', null, function (err, docs) { }); });res: response的缩写, 响应的数据 (通常用res.send() 给前端调用接口)
//这里就是前端获取接口时,取得的数据,当前定义为对象{msg,code,data,token} res.send({ msg: '注册成功~',//提示信息 code: 200,//提示编号 data: result,//数据库查询后,返回的数据 token: token //登录接口所需的返回参数,用于登录校验 });next 则是前往下一个中间件,执行相同路径的下一个方法。
理解完这个思路后,下面就是vue部分调用接口了,以及继续完善自己想要的部分内容
3:vue项目
main.js
// The Vue build version to load with the `import` command // (runtime-only or standalone) has been set in webpack.base.conf with an alias. import Vue from 'vue' import ElementUI from 'element-ui' import 'element-ui/lib/theme-chalk/index.css' import App from './App' import router from './router' import store from '@/store/store' // 引入css import '@/styles/index.scss' Vue.use(ElementUI) Vue.config.productionTip = false // 注册一个全局守卫,作用是在路由跳转前,对路由进行判断,防止未登录的用户跳转到其他需要登录的页面去 router.beforeEach((to, from, next) => { let token = localStorage.getItem('mytoken') // 如果已经登录,那我不干涉你,让你随便访问 if (token) { next() } else { // 判断是否前往注册 if(to.path == '/register'){ next() }else{ if(to.path !== '/login') { // 如果没有登录,但你访问其他需要登录的页面,那我就让你跳到登录页面去 next({path: '/login'}) } else { // 如果登录,那就不干涉你,让你访问 next() } } } }) /* eslint-disable no-new */ new Vue({ el: '#app', router, store, components: { App }, template: '<App/>' })Login.vue
<template> <div class="login"> <el-form ref="form" :model="form" class="container" :rules="rules"> <el-form-item> <div class="avatar"> <img src="../assets/avatar.jpg" alt=""> </div> </el-form-item> <el-form-item prop="username"> <el-input v-model="form.phone" placeholder="账户" prefix-icon="myicon myicon-user"></el-input> </el-form-item> <el-form-item prop="password"> <el-input v-model="form.pwd" placeholder="密码" prefix-icon="myicon myicon-key" type="password" @keydown.native.enter="loginSubmit('form')"></el-input> </el-form-item> <el-form-item> <el-button type="primary" class="login-btn" @click="loginSubmit('form')">登录</el-button> </el-form-item> <el-form-item> <el-button class="login-btn" @click="registerSubmit()">注册</el-button> </el-form-item> </el-form> </div> </template> <script> // 引入api接口方法 import { checkUser } from '@/api/index.js' export default { data() { return { form: { phone: '', pwd: '' }, rules: { phone: [{ required: true, message: '请输入用户名', trigger: 'blur' }], pwd: [{ required: true, message: '请输入密码', trigger: 'blur' }] } } }, methods: { loginSubmit() { checkUser(this.form).then(res => { console.log(res) if(res.data.code === 200) { localStorage.setItem('mytoken', res.data.token) this.$message({ type: 'success', message: "登录成功" }) setTimeout(() => { this.$router.push({ name: 'Home' }) }, 1000); } else { // 如果失败,展示提示信息 this.$message({ type: 'error', message: res.data.msg }) } }) }, registerSubmit() { this.$router.push({ name: 'Register' }) } } } </script> <style lang="scss" scoped> .login { position: fixed; width: 100%; height: 100%; background-color: #2f4050; .container { position: absolute; left: 0; right: 0; width: 400px; padding: 0px 40px 15px 40px; margin: 200px auto; background: white; .avatar { position: relative; left: 50%; width: 120px; height: 120px; margin-left: -60px; margin-top: -60px; box-sizing: border-box; border-radius: 50%; border: 10px solid #fff; box-shadow: 0 1px 5px #ccc; overflow: hidden; img{ width: 100%; } } .login-btn { width: 100%; } } } </style>总结一下:开发过程中遇到的很多问题,百度居多,重要的是,要理解怎么做,下面我会贴出源码,写的不好之处勿怪。