Beberapa waktu lalu, saya mendiskusikan jalur kariernya dengan seorang kolega di perusahaan yang telah beralih dari teknologi ke produk, dan dia mengatakan sesuatu yang sangat saya yakini:
“Jangan membatasi diri pada bidang tertentu. Transformasi dari teknologi ke produk pertama-tama adalah perubahan pemikiran. Anda telah bekerja di front end. Saat berinteraksi dengan data, Anda hanya tahu cara memasukkannya, tetapi Anda tidak tahu bagaimana hasilnya. Ini adalah batasannya.
Itu seperti sebuah pencerahan. Ketika saya mempelajari Vue, saya melihat proyek registrasi dan login. Saya cukup mengikutinya dan memulai proyek Vue, memperkenalkan koa dan mongodb, dan mengimplementasikan input-pengembalian penerimaan server-klien .
Proyek ini dibangun berdasarkan vue-cli, menggunakan metode token untuk memverifikasi login pengguna, dan mengimplementasikan fungsi seperti mendaftar ke database, membaca pengguna, dan menghapus pengguna. Artikel ini mengasumsikan bahwa pembaca memiliki landasan tertentu dalam node dan vue, sehingga bagian dasarnya tidak akan dijelaskan secara detail.
Lingkungan sistem: MacOS 10.13.3
Instal menggunakan cermin Taobao
$ npm install -g cnpm --registry=https://registry.npm.taobao.org
Kemudian ubah semua npm install menjadi cnpm install
Untuk memperjelas ide proyek dan teknologi yang dipilih, diagram digambar agar mudah dipahami.
1.Inisialisasi proyek
$ npm install
2. Mulai proyek
$ npm run dev
3. Mulai MongoDB
$ mongod --dbpath XXX
xxx adalah jalur ke folder data dalam proyek (Anda juga dapat membuat yang baru, database digunakan untuk menyimpan data), atau Anda dapat menyeretnya langsung ke terminal.
4. Mulai servernya
$ node server.js
Saya memilih Element-UI Ele.me sebagai perpustakaan UI pilihan saya untuk vue. Lainnya seperti iview dan vue-strap sepertinya tidak sekomprehensif ele.
$ npm i element-ui -S
//在项目里的mian.js里增加下列代码
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
Gunakan peralihan tab di UI untuk beralih antara antarmuka registrasi dan login, gunakan komponen login sebagai antarmuka utama seluruh sistem login, dan komponen register sebagai komponen independen. Silakan merujuk ke situs resmi untuk metode komposisi Element-UI, validasi formulir, dan API lainnya.
//login组件
<template>
<div class="login">
<el-tabs v-model="activeName" @tab-click="handleClick">
<el-tab-pane label="登录" name="first">
<el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
<el-form-item label="名称" prop="name">
<el-input v-model="ruleForm.name"></el-input>
</el-form-item>
<el-form-item label="密码" prop="pass">
<el-input type="password" v-model="ruleForm.pass" auto-complete="off"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('ruleForm')">登录</el-button>
<el-button @click="resetForm('ruleForm')">重置</el-button>
</el-form-item>
</el-form>
</el-tab-pane>
<el-tab-pane label="注册" name="second">
<register></register>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script>
import register from '@/components/register'
export default {
data() {
var validatePass = (rule, value, callback) => {
if (value === '') {
callback(new Error('请输入密码'));
} else {
if (this.ruleForm.checkPass !== '') {
this.$refs.ruleForm.validateField('checkPass');
}
callback();
}
};
return {
activeName: 'first',
ruleForm: {
name: '',
pass: '',
checkPass: '',
},
rules: {
name: [
{ required: true, message: '请输入您的名称', trigger: 'blur' },
{ min: 2, max: 5, message: '长度在 2 到 5 个字符', trigger: 'blur' }
],
pass: [
{ required: true, validator: validatePass, trigger: 'blur' }
]
},
};
},
methods: {
//选项卡切换
handleClick(tab, event) {
},
//重置表单
resetForm(formName) {
this.$refs[formName].resetFields();
},
//提交表单
submitForm(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
this.$message({
type: 'success',
message: '登录成功'
});
this.$router.push('HelloWorld');
} else {
console.log('error submit!!');
return false;
}
});
},
},
components: {
register
}
}
</script>
<style rel="stylesheet/scss" lang="scss">
.login {
width: 400px;
margin: 0 auto;
}
#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;
}
.el-tabs__item {
text-align: center;
width: 60px;
}
</style>
Selanjutnya adalah mendaftarkan komponen
//register组件
<template>
<el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
<el-form-item label="名称" prop="name">
<el-input v-model="ruleForm.name"></el-input>
</el-form-item>
<el-form-item label="密码" prop="pass">
<el-input type="password" v-model="ruleForm.pass" auto-complete="off"></el-input>
</el-form-item>
<el-form-item label="确认密码" prop="checkPass">
<el-input type="password" v-model="ruleForm.checkPass" auto-complete="off"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('ruleForm')">注册</el-button>
<el-button @click="resetForm('ruleForm')">重置</el-button>
</el-form-item>
</el-form>
</template>
<script>
export default {
data() {
var validatePass = (rule, value, callback) => {
if (value === '') {
callback(new Error('请输入密码'));
} else {
if (this.ruleForm.checkPass !== '') {
this.$refs.ruleForm.validateField('checkPass');
}
callback();
}
};
var validatePass2 = (rule, value, callback) => {
if (value === '') {
callback(new Error('请再次输入密码'));
} else if (value !== this.ruleForm.pass) {
callback(new Error('两次输入密码不一致!'));
} else {
callback();
}
};
return {
activeName: 'second',
ruleForm: {
name: '',
pass: '',
checkPass: '',
},
rules: {
name: [
{ required: true, message: '请输入您的名称', trigger: 'blur' },
{ min: 2, max: 5, message: '长度在 2 到 5 个字符', trigger: 'blur' }
],
pass: [
{ required: true, validator: validatePass, trigger: 'blur' }
],
checkPass: [
{ required: true, validator: validatePass2, trigger: 'blur' }
],
}
};
},
methods: {
submitForm(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
this.$message({
type: 'success',
message: '注册成功'
});
// this.activeName: 'first',
} else {
console.log('error submit!!');
return false;
}
});
},
resetForm(formName) {
this.$refs[formName].resetFields();
}
}
}
</script>
vue-router adalah inti dari Vue untuk membuat proyek satu halaman. Aplikasi dapat dibuat dengan menggabungkan komponen. Yang harus kita lakukan adalah memetakan komponen ke rute dan kemudian memberi tahu vue-router di mana harus merendernya. Kode di atas sudah melibatkan beberapa peralihan perutean. Mari kita tingkatkan peruteannya sekarang:
$ cnpm i vue-router
import Router from 'vue-router'
Vue.use(Router)
Buat router (folder)/index.js baru di bawah folder src. Kami telah memperkenalkan tiga komponen:
Halaman tampilan HelloWorld setelah login
antarmuka masuk masuk utama
komponen register register
Gunakan router.beforeEach routing guard untuk mengatur halaman yang perlu login terlebih dahulu. Gunakan kolom requireAuth untuk menentukan apakah rute memerlukan izin login. Rute yang memerlukan izin akan dicegat, dan kemudian akan ditentukan apakah ada token (token akan dibahas di bawah). melompat ke halaman login.
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import login from '@/components/login'
import register from '@/components/register'
Vue.use(Router)
const router = new Router({
mode: 'history',
routes: [{
path: '/',
name: 'home',
component: HelloWorld,
meta: {
requiresAuth: true
}
},
{
path: '/HelloWorld',
name: 'HelloWorld',
component: HelloWorld,
},
{
path: '/login',
name: 'login',
component: login,
},
{
path: '/register',
name: 'register',
component: register,
},
]
});
//注册全局钩子用来拦截导航
router.beforeEach((to, from, next) => {
//获取store里面的token
let token = store.state.token;
//判断要去的路由有没有requiresAuth
if (to.meta.requiresAuth) {
if (token) {
next();
} else {
next({
path: '/login',
query: { redirect: to.fullPath } // 将刚刚要去的路由path作为参数,方便登录成功后直接跳转到该路由
});
}
} else {
next();
}
});
export default router;
Kita dapat melihat bahwa token di penjaga perutean diperoleh dari penyimpanan, yang berarti kita menyimpan berbagai status token di penyimpanan dan melakukan operasi seperti pengambilan, pembaruan, dan penghapusan. Hal ini memerlukan pengenalan manajemen status vuex .
Jelaskan mengapa halaman registrasi dan login sederhana memerlukan penggunaan vuex: Pengoperasian setiap komponen kita dalam proyek pada dasarnya memerlukan perolehan token untuk verifikasi. Jika komponen A menyimpan token, perolehan token oleh komponen B melibatkan komunikasi komponen. yang akan sangat membosankan. Dengan diperkenalkannya vuex, bukan lagi komunikasi antar komponen, melainkan komunikasi antara komponen dan toko, yang sederhana dan nyaman.
$ cnpm i vuex --S
Perkenalkan store di main.js, dan tambahkan store ke instance vue.
//引入store
import store from './store'
Kemudian perkenalkan pada komponen yang perlu menggunakan vuex
//store index.js
import Vuex from 'vuex'
Vue.use(Vuex)
Buat toko (folder)/index.js baru di bawah folder src
//store index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);
//初始化时用sessionStore.getItem('token'),这样子刷新页面就无需重新登录
const state = {
token: window.sessionStorage.getItem('token'),
username: ''
};
const mutations = {
LOGIN: (state, data) => {
//更改token的值
state.token = data;
window.sessionStorage.setItem('token', data);
},
LOGOUT: (state) => {
//登出的时候要清除token
state.token = null;
window.sessionStorage.removeItem('token');
},
USERNAME: (state, data) => {
//把用户名存起来
state.username = data;
window.sessionStorage.setItem('username', data);
}
};
const actions = {
UserLogin({ commit }, data){
commit('LOGIN', data);
},
UserLogout({ commit }){
commit('LOGOUT');
},
UserName({ commit }, data){
commit('USERNAME', data);
}
};
export default new Vuex.Store({
state,
mutations,
actions
});
Anda dapat melihat bahwa kami mengirimkan mutasi melalui tindakan, mengubah token, menghapus token, dan menyimpan nama pengguna.
Saat Anda memulai proyek saat ini, Anda dapat melihat antarmuka registrasi awal dan login.Klik tombol registrasi atau login untuk beralih ke antarmuka yang sesuai, dan ada verifikasi formulir dasar.
Kami telah menulis antarmuka dasar, dan langkah selanjutnya adalah mengirim data formulir ke latar belakang dan melakukan serangkaian pemrosesan. Tidak masalah jika belum ada antarmuka back-end. Mari kita tulis permintaan aksio front-end terlebih dahulu.
Komunikasi Vue menggunakan sumber daya vue sebelumnya, dan terdapat banyak kendala. Sampai vue2.0 hadir, tinggalkan saja vue-resource dan gunakan axios .
Enkapsulasi ajax, digunakan untuk mengirim permintaan dan memperoleh data secara asinkron. Klien HTTP berbasis janji, cocok untuk: browser dan node.js.
Deskripsi API khusus dalam bahasa Mandarin: https://www.kancloud.cn/yunye/axios/234845
$ cnpm i -S axios
import axios from 'axios'
Pada bagian pengaturan vue-router, penjaga perutean ditambahkan untuk mencegat rute yang memerlukan login, namun metode ini hanya merupakan kontrol perutean front-end yang sederhana dan tidak dapat mencegah pengguna mengakses rute yang memerlukan izin login. Saat token habis masa berlakunya, token tersebut masih disimpan secara lokal. Saat ini, ketika Anda mengakses rute yang memerlukan izin masuk, Anda sebenarnya harus meminta pengguna untuk masuk lagi. Saat ini, pencegat + kode status http yang dikembalikan oleh antarmuka backend diperlukan untuk menilai.
Buat axios.js baru di bawah folder src (level yang sama dengan App.vue)
//axios.js
import axios from 'axios'
import store from './store'
import router from './router'
//创建axios实例
var instance = axios.create({
timeout: 5000, //请求超过5秒即超时返回错误
headers: { 'Content-Type': 'application/json;charset=UTF-8' },
});
//request拦截器
instance.interceptors.request.use(
config => {
//判断是否存在token,如果存在的话,则每个http header都加上token
if (store.state.token) {
config.headers.Authorization = `token ${store.state.token}`;
}
return config;
}
);
//respone拦截器
instance.interceptors.response.use(
response => {
return response;
},
error => { //默认除了2XX之外的都是错误的,就会走这里
if (error.response) {
switch (error.response.status) {
case 401:
router.replace({ //跳转到登录页面
path: 'login',
query: { redirect: router.currentRoute.fullPath } // 将跳转的路由path作为参数,登录成功后跳转到该路由
});
}
}
return Promise.reject(error.response);
}
);
export default {
//用户注册
userRegister(data){
return instance.post('/api/register', data);
},
//用户登录
userLogin(data){
return instance.post('/api/login', data);
},
//获取用户
getUser(){
return instance.get('/api/user');
},
//删除用户
delUser(data){
return instance.post('/api/delUser', data);
}
}
Kode tersebut akhirnya memperlihatkan empat metode permintaan, yang sesuai dengan pengguna mendaftar, login, memperoleh (pengguna), dan menghapus (delUser), dan semuanya berada di bawah /api.
http://localhost:8080/api/login
http://localhost:8080/api/register
http://localhost:8080/api/user
http://localhost:8080/api/delUser
Nanti kita akan menggunakan keempat metode ini untuk menulis antarmuka backend yang sesuai.
Artikel dimulai dari sini di sisi server. Karena sisi server perlu dibangun bersama dengan database dan komunikasi aman http (jwt), silakan baca bagian ini bersama dengan database dan bab jwt di bawah.
koa2 dapat menggunakan sintaks async/await untuk menghindari penumpukan fungsi panggilan balik yang berulang dan rumit, dan menggunakan ctx untuk mengakses objek Konteks.
Sekarang kami menggunakan koa2 untuk menulis antarmuka layanan API proyek.
$ cnpm i koa
$ cnpm i koa-router -S //koa路由中间件
$ cnpm i koa-bodyparser -S //处理post请求,并把koa2上下文的表单数据解析到ctx.request.body中
const Koa = require('koa');
Buat server.js baru di bawah direktori root proyek sebagai entri startup untuk seluruh server.
//server.js
const Koa = require('koa');
const app = new Koa();
//router
const Router = require('koa-router');
//父路由
const router = new Router();
//bodyparser:该中间件用于post请求的数据
const bodyParser = require('koa-bodyparser');
app.use(bodyParser());
//引入数据库操作方法
const UserController = require('./server/controller/user.js');
//checkToken作为中间件存在
const checkToken = require('./server/token/checkToken.js');
//登录
const loginRouter = new Router();
loginRouter.post('/login', UserController.Login);
//注册
const registerRouter = new Router();
registerRouter.post('/register', UserController.Reg);
//获取所有用户
const userRouter = new Router();
userRouter.get('/user', checkToken, UserController.GetAllUsers);
//删除某个用户
const delUserRouter = new Router();
delUserRouter.post('/delUser', checkToken, UserController.DelUser);
//装载上面四个子路由
router.use('/api',loginRouter.routes(),loginRouter.allowedMethods());
router.use('/api',registerRouter.routes(),registerRouter.allowedMethods());
router.use('/api',userRouter.routes(),userRouter.allowedMethods());
router.use('/api',delUserRouter.routes(),delUserRouter.allowedMethods());
//加载路由中间件
app.use(router.routes()).use(router.allowedMethods());
app.listen(8888, () => {
console.log('The server is running at http://localhost:' + 8888);
});
Seperti dapat dilihat dalam kode, mendapatkan pengguna dan menghapus pengguna memerlukan token verifikasi (lihat bab jwt di bawah untuk detailnya), dan kami telah menggantungkan empat antarmuka di /api, yang konsisten dengan jalur permintaan aksio sebelumnya.
Selain itu, karena port startup proyek kita adalah 8080 dan port yang dipantau oleh antarmuka koa adalah 8888, kita perlu menambahkan yang berikut ini ke konfigurasi dev di file config/index.js:
proxyTable: {
'/api': {
target: 'http://localhost:8888',
changeOrigin: true
}
},
JWT dapat membantu kami melakukan otentikasi identitas selama komunikasi HTTP.
Untuk detail API spesifik, silakan lihat: https://segmentfault.com/a/1190000009494020
1. Klien log in ke server melalui nama pengguna dan kata sandi;
2. Server memverifikasi identitas klien;
3. Server menghasilkan Token untuk pengguna dan mengembalikannya ke klien;
4. Klien menyimpan token ke browser lokal, biasanya dalam cookie (artikel ini menggunakan sessionStorage, tergantung situasinya);
5. Saat klien memulai permintaan, klien perlu membawa Token;
6. Setelah menerima permintaan, server terlebih dahulu memverifikasi Token dan kemudian mengembalikan data. Server tidak perlu menyimpan Token, hanya perlu memverifikasi informasi yang dibawa dalam Token. Tidak peduli server mana yang diakses klien di latar belakang, asalkan dapat lolos verifikasi informasi pengguna.
Di folder server, buat /token (folder) baru di bawah dan tambahkan checkToken.js dan createToken.js untuk menempatkan metode pemeriksaan dan penambahan token masing-masing.
$ cnpm i jsonwebtoken -S
const jwt = require('jsonwebtoken');
module.exports = function(user_id){
const token = jwt.sign({user_id: user_id}, 'zhangzhongjie', {expiresIn: '60s'
});
return token;
};
Saat membuat token, kami menggunakan nama pengguna sebagai atribut JWT Payload, menyetel kunci ke 'zhangzhongjie', dan menyetel waktu kedaluwarsa token ke 60 detik. Artinya setelah login, menyegarkan halaman dalam waktu 60 detik tidak perlu login lagi.
const jwt = require('jsonwebtoken');
//检查token是否过期
module.exports = async ( ctx, next ) => {
//拿到token
const authorization = ctx.get('Authorization');
if (authorization === '') {
ctx.throw(401, 'no token detected in http headerAuthorization');
}
const token = authorization.split(' ')[1];
let tokenContent;
try {
tokenContent = await jwt.verify(token, 'zhangzhongjie');//如果token过期或验证失败,将抛出错误
} catch (err) {
ctx.throw(401, 'invalid token');
}
await next();
};
Dapatkan tokennya terlebih dahulu lalu gunakan jwt.verify untuk memverifikasinya. Perhatikan bahwa kuncinya harus sesuai dengan kunci 'zhangzhongjie' dari createToken.js. Jika token kosong, kedaluwarsa, atau gagal verifikasi, kesalahan 401 akan muncul dan mengharuskan Anda masuk lagi.
MongoDB adalah sistem manajemen basis data berorientasi dokumen yang dirancang untuk menyediakan solusi penyimpanan data berkinerja tinggi dan terukur untuk aplikasi WEB. Sangat mudah menggunakan node untuk terhubung ke MongoDB.
$ cnpm i mongoose -S
Ada beberapa cara untuk terhubung ke MongoDB. Di sini kita menggunakan koneksi. connection adalah referensi default modul luwak dan mengembalikan objek Connection.
Buat db.js baru di folder server sebagai entri koneksi database.
//db.js
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/vue-login');
let db = mongoose.connection;
// 防止Mongoose: mpromise 错误
mongoose.Promise = global.Promise;
db.on('error', function(){
console.log('数据库连接出错!');
});
db.on('open', function(){
console.log('数据库连接成功!');
});
//声明schema
const userSchema = mongoose.Schema({
username: String,
password: String,
token: String,
create_time: Date
});
//根据schema生成model
const User = mongoose.model('User', userSchema)
module.exports = User;
Selain koneksi yang kita gunakan, ada juga metode koneksi *connect() dan createConnection()*.
Skema mendefinisikan templat tabel sehingga jenis dokumen ini memiliki komposisi dan mode penyimpanan tertentu dalam database. Tapi itu hanya mendefinisikan seperti apa Dokumen itu. Sedangkan untuk membuat dokumen dan melakukan berbagai operasi pada dokumen (menambah, menghapus, memodifikasi, dan memeriksa), itu dilakukan melalui model yang sesuai kita dapat menggunakan Model, artinya model adalah pegangan yang dapat kita operasikan.
Setelah mengkompilasi model, kita mendapatkan model bernama User .
Perhatikan tabel skema yang Anda tentukan di sini. Penyimpanan data harus sesuai dengan tabel ini saat menulis dan mendaftarkannya ke database nanti.
Buat pengontrol (folder)/user.js baru di bawah folder server untuk menyimpan metode operasi database.
Instal beberapa plug-in fungsional terlebih dahulu
$ cnpm i moment -s //用于生成时间
$ cnpm i objectid-to-timestamp -s //用于生成时间
$ cnpm i sha1 -s //安全哈希算法,用于密码加密
//user.js
const User = require('../db.js').User;
//下面这两个包用来生成时间
const moment = require('moment');
const objectIdToTimestamp = require('objectid-to-timestamp');
//用于密码加密
const sha1 = require('sha1');
//createToken
const createToken = require('../token/createToken.js');
//数据库的操作
//根据用户名查找用户
const findUser = (username) => {
return new Promise((resolve, reject) => {
User.findOne({ username }, (err, doc) => {
if(err){
reject(err);
}
resolve(doc);
});
});
};
//找到所有用户
const findAllUsers = () => {
return new Promise((resolve, reject) => {
User.find({}, (err, doc) => {
if(err){
reject(err);
}
resolve(doc);
});
});
};
//删除某个用户
const delUser = function(id){
return new Promise(( resolve, reject) => {
User.findOneAndRemove({ _id: id }, err => {
if(err){
reject(err);
}
console.log('删除用户成功');
resolve();
});
});
};
//登录
const Login = async ( ctx ) => {
//拿到账号和密码
let username = ctx.request.body.name;
let password = sha1(ctx.request.body.pass);//解密
let doc = await findUser(username);
if(!doc){
console.log('检查到用户名不存在');
ctx.status = 200;
ctx.body = {
info: false
}
}else if(doc.password === password){
console.log('密码一致!');
//生成一个新的token,并存到数据库
let token = createToken(username);
console.log(token);
doc.token = token;
await new Promise((resolve, reject) => {
doc.save((err) => {
if(err){
reject(err);
}
resolve();
});
});
ctx.status = 200;
ctx.body = {
success: true,
username,
token, //登录成功要创建一个新的token,应该存入数据库
create_time: doc.create_time
};
}else{
console.log('密码错误!');
ctx.status = 200;
ctx.body = {
success: false
};
}
};
//注册
const Reg = async ( ctx ) => {
let user = new User({
username: ctx.request.body.name,
password: sha1(ctx.request.body.pass), //加密
token: createToken(this.username), //创建token并存入数据库
create_time: moment(objectIdToTimestamp(user._id)).format('YYYY-MM-DD HH:mm:ss'),//将objectid转换为用户创建时间
});
//将objectid转换为用户创建时间(可以不用)
user.create_time = moment(objectIdToTimestamp(user._id)).format('YYYY-MM-DD HH:mm:ss');
let doc = await findUser(user.username);
if(doc){
console.log('用户名已经存在');
ctx.status = 200;
ctx.body = {
success: false
};
}else{
await new Promise((resolve, reject) => {
user.save((err) => {
if(err){
reject(err);
}
resolve();
});
});
console.log('注册成功');
ctx.status = 200;
ctx.body = {
success: true
}
}
};
//获得所有用户信息
const GetAllUsers = async( ctx ) => {
//查询所有用户信息
let doc = await findAllUsers();
ctx.status = 200;
ctx.body = {
succsess: '成功',
result: doc
};
};
//删除某个用户
const DelUser = async( ctx ) => {
//拿到要删除的用户id
let id = ctx.request.body.id;
await delUser(id);
ctx.status = 200;
ctx.body = {
success: '删除成功'
};
};
module.exports = {
Login,
Reg,
GetAllUsers,
DelUser
};
Metode di atas merupakan inti dari operasi database dalam proyek. Mari kita analisa.
Pertama, tiga metode dasar umum didefinisikan: findUser, findAllUsers, dan delUser. Diantaranya, findUser harus memasukkan parameter nama pengguna , dan delUser harus memasukkan parameter id .
Dapatkan informasi formulir yang dikirimkan oleh posting pengguna, Pengguna baru yang sebelumnya dirancang sesuai dengan database dan dikompilasi menjadi model, dan nama pengguna yang diperoleh, kata sandi (perlu dienkripsi dengan hash sha1), token (menggunakan yang dibuat sebelumnya metode createToken, Dan gunakan nama pengguna sebagai parameter payload jwt), dan hemat waktu pembuatan.
Saat ini, Anda harus terlebih dahulu mencari database untuk melihat apakah nama pengguna ada. Jika ada, maka akan gagal. Jika tidak, pengguna akan disimpan dalam database dan kesuksesan akan dikembalikan.
Dapatkan informasi formulir posting pengguna, nama pengguna dan kata sandi (pendaftaran di-hash dan perlu didekripsi saat ini). Cari nama pengguna dari database untuk menentukan apakah nama pengguna tersebut ada. Jika tidak ada kesalahan pengembalian, tentukan apakah kata sandi yang disimpan dalam database konsisten dengan kata sandi yang dikirimkan oleh pengguna pengguna dan disimpan dalam database.
Cukup rangkum metode findAllUsers publik di atas dan masukkan informasinya ke dalam hasilnya, sehingga halaman helloworld dapat memperoleh data ini dan menampilkannya nanti.
Perhatikan bahwa Anda harus terlebih dahulu mendapatkan ID pengguna yang perlu dihapus dan meneruskannya sebagai parameter.
Setelah menulis metode ini, Anda dapat meningkatkan fungsi registrasi dan login yang sebelumnya tidak sempurna.
Ketika kita menyelesaikan registrasi dan data disimpan dalam database, kita ingin memeriksa data yang baru saja didaftarkan dan disimpan dalam database, dan kita perlu menggunakan alat visualisasi database. Saya menggunakan MongoBooster yang mudah dioperasikan.
Seperti yang Anda lihat pada gambar di bawah, dua data yang didaftarkan pada contoh meliputi id, nama pengguna, kata sandi, token, dan waktu. Rangkaian kata sandi yang panjang itu dikompilasi karena enkripsi hash.
Tambahkan kode berikut setelah validasi formulir di register.vue
//register.vue
if (valid) {
axios.userRegister(this.ruleForm)
.then(({}) => {
if (data.success) {
this.$message({
type: 'success',
message: '注册成功'
});
} else {
this.$message({
type: 'info',
message: '用户名已经存在'
});
}
})
}
Kami tidak mengirimkan data apa pun sebelumnya di komponen login. Sekarang kami menambahkan serangkaian metode untuk menyelesaikan operasi login setelah verifikasi berhasil: Memperkenalkan aksio
import axios from '../axios.js'
Kemudian tambahkan kode berikut setelah verifikasi formulir di login.vue
//login.vue
if (valid) {
axios.userLogin(this.ruleForm)
.then(({ data }) => {
//账号不存在
if (data.info === false) {
this.$message({
type: 'info',
message: '账号不存在'
});
return;
}
//账号存在
if (data.success) {
this.$message({
type: 'success',
message: '登录成功'
});
//拿到返回的token和username,并存到store
let token = data.token;
let username = data.username;
this.$store.dispatch('UserLogin', token);
this.$store.dispatch('UserName', username);
//跳到目标页
this.$router.push('HelloWorld');
}
});
}
Kirimkan data formulir ke latar belakang, kembalikan status data, dan tentukan apakah akun tersebut ada atau tidak. Setelah login berhasil, Anda perlu mendapatkan token dan nama pengguna yang dikembalikan, menyimpannya di toko, dan melompat ke halaman target HelloWorld.
Setelah berhasil mendaftar dan login, akhirnya kita sampai pada tampilan halaman sebenarnya—helloworld!
Mari kita tingkatkan komponen ini sehingga menampilkan semua nama pengguna yang terdaftar saat ini dan memberikan tombol hapus.
//Helloworld.vue
<template>
<div class="hello">
<ul>
<li v-for="(item,index) in users" :key="item._id">
{{ index + 1 }}.{{ item.username }}
<el-button @click="del_user(index)">删除</el-button>
</li>
</ul>
<el-button type="primary" @click="logout()">注销</el-button>
</div>
</template>
<script>
import axios from '../axios.js'
export default {
name: 'HelloWorld',
data () {
return {
users:''
}
},
created(){
axios.getUser().then((response) => {
if(response.status === 401){
//不成功跳转回登录页
this.$router.push('/login');
//并且清除掉这个token
this.$store.dispatch('UserLogout');
}else{
//成功了就把data.result里的数据放入users,在页面展示
this.users = response.data.result;
}
})
},
methods:{
del_user(index, event){
let thisID = {
id:this.users[index]._id
}
axios.delUser(thisID)
.then(response => {
this.$message({
type: 'success',
message: '删除成功'
});
//移除节点
this.users.splice(index, 1);
}).catch((err) => {
console.log(err);
});
},
logout(){
//清除token
this.$store.dispatch('UserLogout');
if (!this.$store.state.token) {
this.$router.push('/login')
this.$message({
type: 'success',
message: '注销成功'
})
} else {
this.$message({
type: 'info',
message: '注销失败'
})
}
},
}
}
</script>
<style scoped>
h1, h2 {
font-weight: normal;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
.hello {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
width: 400px;
margin: 60px auto 0 auto;
}
</style>
Halaman keluarannya relatif sederhana. Berikut adalah beberapa poin penting:
1. Antarmuka getUser() harus diminta segera setelah instance dibuat ( create() ). Jika permintaan gagal, token harus dihapus. Jika permintaan berhasil, data yang dikembalikan harus dimasukkan ke halaman pengguna rendering.
2. ID ini harus ditulis dalam format objek, jika tidak, kesalahan akan dilaporkan
3. Hapus token saat logout
Mengubah cara berpikir masyarakat memang merupakan hal tersulit. Menurut prosesnya, koa harus mendesain antarmukanya terlebih dahulu, kemudian front-end akan membuat permintaan berdasarkan antarmuka ini. Namun sebaliknya, saya menulis permintaan front-end terlebih dahulu, lalu merumuskan antarmuka berdasarkan permintaan tersebut.
Tentu saja, saya juga menemui banyak kesulitan: ketika saya menyelesaikan halaman tampilan front-end dan aksio ditulis, saya terjebak dalam waktu lama dalam menggunakan koa untuk menulis antarmuka. Saya tidak tahu sama sekali , "Saya hanya tahu cara memasukkan data, bukan cara memasukkannya." Kemudian saya menemukan kesalahan antarmuka 500 dan melakukan debug untuk waktu yang lama. Alasan utamanya adalah saya tidak memiliki konsep untuk men-debug antarmuka. Pada akhirnya, bos perusahaan Langya membantu menyelesaikan masalah tersebut.