Vor einiger Zeit besprach ich seinen Karriereweg mit einem Kollegen im Unternehmen, der von der Technologie zum Produkt gewechselt war, und er sagte etwas, woran ich zutiefst glaubte:
„Beschränken Sie sich nicht auf ein bestimmtes Feld. Der Wandel von der Technologie zum Produkt ist zunächst einmal ein Umdenken. Sie haben am Frontend gearbeitet. Bei der Interaktion mit Daten wissen Sie nur, wie man sie eingibt, aber Sie.“ Ich weiß nicht, wie es herauskommt. Das ist eine Einschränkung.
Es war wie eine Erleuchtung, als ich ein Registrierungs- und Anmeldeprojekt sah, ein Vue-Projekt startete, Koa und Mongodb einführte und den gesamten Datenbankprozess implementierte .
Dieses Projekt basiert auf vue-cli, verwendet die Token-Methode zur Überprüfung der Benutzeranmeldung und implementiert Funktionen wie die Registrierung in der Datenbank, das Lesen von Benutzern und das Löschen von Benutzern. Der Artikel geht davon aus, dass der Leser über eine gewisse Grundlage in Node und Vue verfügt, sodass die grundlegenden Teile nicht im Detail beschrieben werden.
Systemumgebung: MacOS 10.13.3
Installation mit Taobao-Spiegel
$ npm install -g cnpm --registry=https://registry.npm.taobao.org
Ändern Sie dann alle npm-Installationen in cnpm-Installationen
Um die Projektideen und ausgewählten Technologien klarer zu machen, wird zum besseren Verständnis ein Diagramm gezeichnet.
1.Initialisieren Sie das Projekt
$ npm install
2. Starten Sie das Projekt
$ npm run dev
3. Starten Sie MongoDB
$ mongod --dbpath XXX
xxx ist der Pfad zum Datenordner im Projekt (Sie können auch einen neuen erstellen, die Datenbank wird zum Speichern von Daten verwendet) oder Sie können ihn direkt in das Terminal ziehen.
4. Starten Sie den Server
$ node server.js
Ich habe die Element-UI von Ele.me als meine bevorzugte UI-Bibliothek für Vue ausgewählt. Andere wie iview und vue-strap scheinen nicht so umfassend zu sein wie ele.
$ npm i element-ui -S
//在项目里的mian.js里增加下列代码
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
Verwenden Sie den Tab-Wechsel in der Benutzeroberfläche, um zwischen den Registrierungs- und Anmeldeschnittstellen zu wechseln, verwenden Sie die Anmeldekomponente als Hauptschnittstelle des gesamten Anmeldesystems und die Registrierungskomponente als unabhängige Komponente. Informationen zur Kompositionsmethode von Element-UI, zur Formularvalidierung und anderen APIs finden Sie auf der offiziellen Website.
//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>
Als nächstes müssen Sie die Komponente registrieren
//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 ist der Kern von Vue zum Erstellen von Einzelseitenprojekten. Wir müssen Komponenten Routen zuordnen und Vue-Router dann mitteilen, wo sie gerendert werden sollen. Der obige Code beinhaltet bereits einige Routing-Umschaltungen. Lassen Sie uns jetzt das Routing verbessern:
$ cnpm i vue-router
import Router from 'vue-router'
Vue.use(Router)
Erstellen Sie einen neuen Router (Ordner)/index.js im Ordner src. Wir haben drei Komponenten eingeführt:
HelloWorld-Anzeigeseite nach der Anmeldung
Login Login Hauptschnittstelle
Register Registerkomponente
Verwenden Sie router.beforeEach Routing Guard, um die Seite festzulegen, die zuerst angemeldet werden muss. Verwenden Sie das Feld „requiresAuth“ , um zu bestimmen, ob für die Route Anmeldeberechtigungen erforderlich sind. Anschließend wird ermittelt, ob ein Token vorhanden ist (das Token wird weiter unten erläutert). Wenn nicht, melden Sie sich direkt an. Springen Sie zur Anmeldeseite.
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;
Wir können sehen, dass das Token im Routing Guard aus dem Store abgerufen wird, was bedeutet, dass wir die verschiedenen Zustände des Tokens im Store speichern und Vorgänge wie Abrufen, Aktualisieren und Löschen ausführen. Dies erfordert die Einführung der Vuex-Statusverwaltung .
Erklären Sie, warum eine einfache Registrierungs- und Anmeldeseite die Verwendung von vuex erfordert: Der Betrieb jeder unserer Komponenten im Projekt erfordert grundsätzlich den Erhalt eines Tokens zur Überprüfung. Wenn Komponente A einen Token speichert, beinhaltet der Erwerb des Tokens die Komponentenkommunikation. was sehr mühsam wäre. Mit der Einführung von Vuex ist nicht mehr die Kommunikation zwischen Komponenten, sondern die Kommunikation zwischen Komponenten und dem Geschäft einfach und bequem.
$ cnpm i vuex --S
Führen Sie den Store in main.js ein und fügen Sie den Store zur Vue-Instanz hinzu.
//引入store
import store from './store'
Führen Sie es dann in die Komponenten ein, die Vuex verwenden müssen
//store index.js
import Vuex from 'vuex'
Vue.use(Vuex)
Erstellen Sie einen neuen Store (Ordner)/index.js im Ordner 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
});
Sie können sehen, dass wir Mutationen durch Aktionen übermitteln, Token ändern, Token löschen und Benutzernamen speichern.
Wenn Sie das Projekt zu diesem Zeitpunkt starten, wird die vorläufige Registrierungs- und Anmeldeoberfläche angezeigt. Klicken Sie auf die Schaltfläche „Registrierung“ oder „Anmelden“, um zur entsprechenden Schnittstelle zu wechseln. Nach der Anmeldung gelangen Sie zur Halloworld-Seite.
Wir haben die grundlegende Schnittstelle geschrieben. Der nächste Schritt besteht darin, die Formulardaten an den Hintergrund zu senden und eine Reihe von Verarbeitungen durchzuführen. Es spielt keine Rolle, ob es noch keine Back-End-Schnittstelle gibt. Schreiben wir zuerst die Front-End-Axios-Anfrage.
Die Kommunikation von Vue nutzte zuvor Vue-Ressourcen und es gab viele Fallstricke. Bis vue2.0 kommt, geben Sie einfach vue-resource auf und verwenden Sie axios .
Kapseln Sie Ajax, das zum asynchronen Senden von Anforderungen und Abrufen von Daten verwendet wird. Promise-basierter HTTP-Client, geeignet für: Browser und node.js.
Spezifische API-Beschreibung auf Chinesisch: https://www.kancloud.cn/yunye/axios/234845
$ cnpm i -S axios
import axios from 'axios'
Beim Einrichten des Vue-Routers werden Routing-Guards hinzugefügt, um Routen abzufangen, für die eine Anmeldung erforderlich ist. Diese Methode ist jedoch nur eine einfache Front-End-Routing-Steuerung und kann Benutzer nicht wirklich daran hindern, auf Routen zuzugreifen, für die Anmeldeberechtigungen erforderlich sind. Wenn das Token abläuft, wird das Token weiterhin lokal gespeichert. Wenn Sie zu diesem Zeitpunkt auf eine Route zugreifen, für die Anmeldeberechtigungen erforderlich sind, sollten Sie den Benutzer tatsächlich bitten, sich erneut anzumelden. Zu diesem Zeitpunkt sind zur Beurteilung Abfangjäger und der von der Backend-Schnittstelle zurückgegebene HTTP-Statuscode erforderlich.
Erstellen Sie eine neue axios.js im Ordner src (gleiche Ebene wie 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);
}
}
Der Code stellt schließlich vier Anforderungsmethoden bereit, die dem Registrieren, Anmelden, Abrufen (Benutzer) und Löschen (delUser) von Benutzern entsprechen. Sie befinden sich alle unter /api. Die vier Anforderungsschnittstellen sind:
http://localhost:8080/api/login
http://localhost:8080/api/register
http://localhost:8080/api/user
http://localhost:8080/api/delUser
Später werden wir diese vier Methoden verwenden, um die entsprechende Backend-Schnittstelle zu schreiben.
Der Artikel beginnt hier auf der Serverseite. Da die Serverseite zusammen mit der Datenbank und der sicheren HTTP-Kommunikation (JWT) erstellt werden muss, lesen Sie diesen Abschnitt bitte in Verbindung mit den folgenden Kapiteln zu Datenbank und JWT.
koa2 kann die Async/Await-Syntax verwenden, um wiederholte und umständliche Verschachtelungen von Rückruffunktionen zu vermeiden, und ctx verwenden, um auf das Kontextobjekt zuzugreifen.
Jetzt verwenden wir koa2, um die API-Serviceschnittstelle des Projekts zu schreiben.
$ cnpm i koa
$ cnpm i koa-router -S //koa路由中间件
$ cnpm i koa-bodyparser -S //处理post请求,并把koa2上下文的表单数据解析到ctx.request.body中
const Koa = require('koa');
Erstellen Sie im Projektstammverzeichnis eine neue server.js als Starteintrag für den gesamten 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);
});
Wie im Code zu sehen ist, sind sowohl für das Erhalten von Benutzern als auch für das Löschen von Benutzern Überprüfungstoken erforderlich (Einzelheiten finden Sie im folgenden JWT-Kapitel). Wir haben die vier Schnittstellen an /api angehängt, was mit dem vorherigen Anforderungspfad von axios übereinstimmt.
Da unser Projektstartport 8080 ist und der von der Koa-Schnittstelle überwachte Port 8888 ist, müssen wir außerdem Folgendes zur Entwicklungskonfiguration in der Datei config/index.js hinzufügen:
proxyTable: {
'/api': {
target: 'http://localhost:8888',
changeOrigin: true
}
},
JWT kann uns bei der Identitätsauthentifizierung während der HTTP-Kommunikation helfen.
Spezifische API-Details finden Sie unter: https://segmentfault.com/a/1190000009494020
1. Der Client meldet sich mit Benutzername und Passwort beim Server an.
2. Der Server überprüft die Identität des Clients.
3. Der Server generiert ein Token für den Benutzer und gibt es an den Client zurück.
4. Der Client speichert das Token im lokalen Browser, normalerweise in einem Cookie (dieser Artikel verwendet sessionStorage, abhängig von der Situation);
5. Wenn der Client eine Anfrage initiiert, muss er das Token tragen;
6. Nach Erhalt der Anfrage überprüft der Server zunächst das Token und gibt dann die Daten zurück. Der Server muss das Token nicht speichern, er muss lediglich die im Token enthaltenen Informationen überprüfen. Unabhängig davon, auf welchen Server der Client im Hintergrund zugreift, solange er die Überprüfung der Benutzerinformationen bestehen kann.
Erstellen Sie im Serverordner unten einen neuen Ordner /token und fügen Sie checkToken.js und createToken.js hinzu, um Methoden zum Überprüfen bzw. Hinzufügen von Token zu platzieren.
$ 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;
};
Beim Erstellen des Tokens verwenden wir den Benutzernamen als Attribut der JWT-Nutzlast, legen den Schlüssel auf „zhangzhongjie“ und die Ablaufzeit des Tokens auf 60 Sekunden fest. Dies bedeutet, dass nach der Anmeldung für die Aktualisierung der Seite innerhalb von 60 Sekunden keine erneute Anmeldung erforderlich ist.
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();
};
Holen Sie sich zuerst das Token und verwenden Sie dann jwt.verify, um es zu überprüfen. Beachten Sie, dass der Schlüssel dem Schlüssel „zhangzhongjie“ von createToken.js entsprechen muss. Wenn das Token leer ist, abläuft oder die Überprüfung fehlschlägt, wird ein 401-Fehler ausgegeben, der Sie zu einer erneuten Anmeldung auffordert.
MongoDB ist ein dokumentenorientiertes Datenbankverwaltungssystem, das skalierbare, leistungsstarke Datenspeicherlösungen für WEB-Anwendungen bereitstellt. Es ist sehr praktisch, den Knoten zum Herstellen einer Verbindung mit MongoDB zu verwenden.
$ cnpm i mongoose -S
Es gibt mehrere Möglichkeiten, eine Verbindung zu MongoDB herzustellen. Hier verwenden wir die Verbindung. Connection ist die Standardreferenz des Mongoose-Moduls und gibt ein Connection-Objekt zurück.
Erstellen Sie im Serverordner eine neue db.js als Datenbankverbindungseintrag.
//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;
Zusätzlich zu der von uns verwendeten Verbindung gibt es auch die Verbindungsmethoden *connect() und createConnection()*.
Schema definiert die Vorlage der Tabelle, sodass dieser Dokumenttyp eine bestimmte Zusammensetzung und einen bestimmten Speichermodus in der Datenbank hat. Es definiert jedoch nur, wie das Dokument aussieht und verschiedene Vorgänge am Dokument ausführt (Hinzufügen, Löschen, Ändern und Überprüfen). Anschließend müssen wir das Benutzerschema in etwas konvertieren Wir können das Modell verwenden, das heißt, das Modell ist der Griff, mit dem wir arbeiten können.
Nach dem Kompilieren des Modells erhalten wir ein Modell mit dem Namen User .
Achten Sie beim späteren Schreiben und Registrieren in der Datenbank auf die Schematabelle, die Sie hier definieren.
Erstellen Sie einen neuen Controller (Ordner)/user.js im Serverordner, um die Betriebsmethoden der Datenbank zu speichern.
Installieren Sie zunächst einige funktionale Plug-Ins
$ 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
};
Die oben genannten Methoden bilden den Kern der Datenbankoperationen im Projekt.
Zunächst werden drei gängige Grundmethoden definiert: findUser, findAllUsers und delUser. Unter diesen muss findUser den Parameter username und delUser den Parameter id übergeben.
Holen Sie sich die vom Benutzer übermittelten Formularinformationen, den neuen Benutzer, der zuvor gemäß der Datenbank entworfen und in ein Modell zusammengestellt wurde, sowie den erhaltenen Benutzernamen, das Passwort (muss mit SHA1-Hash verschlüsselt werden) und das Token (unter Verwendung des zuvor erstellten Codes). createToken-MethodeUnd verwenden Sie den Benutzernamen als Nutzlastparameter von jwt) und sparen Sie die Generierungszeit.
Zu diesem Zeitpunkt müssen Sie zunächst die Datenbank durchsuchen, um festzustellen, ob der Benutzername vorhanden ist. Andernfalls wird der Benutzer in der Datenbank gespeichert und eine Erfolgsmeldung zurückgegeben.
Rufen Sie die Formularinformationen zum Beitrag, Benutzernamen und Passwort des Benutzers ab (die Registrierung ist gehasht und muss zu diesem Zeitpunkt entschlüsselt werden). Durchsuchen Sie den Benutzernamen in der Datenbank, um festzustellen, ob der Benutzername vorhanden ist. Wenn kein Rückgabefehler vorliegt, stellen Sie fest, ob das in der Datenbank gespeicherte Kennwort mit dem vom Benutzer übermittelten Kennwort übereinstimmt. Wenn diese konsistent sind, wird ein neues Token generiert dem Benutzer und wird in der Datenbank gespeichert.
Kapseln Sie einfach die obige öffentliche Methode findAllUsers und fügen Sie die Informationen in das Ergebnis ein, damit die Helloworld-Seite diese Daten abrufen und später anzeigen kann.
Beachten Sie, dass Sie zunächst die zu löschende Benutzer-ID abrufen und als Parameter übergeben müssen.
Nachdem Sie diese Methoden geschrieben haben, können Sie die Registrierungs- und Anmeldefunktionen verbessern, die zuvor nicht perfekt waren.
Wenn wir die Registrierung abschließen und die Daten in der Datenbank gespeichert sind, möchten wir die gerade registrierten und in der Datenbank gespeicherten Daten überprüfen und müssen Datenbankvisualisierungstools verwenden. Ich verwende MongoBooster , das einfach zu bedienen ist.
Wie Sie der Abbildung unten entnehmen können, umfassen die beiden im Beispiel registrierten Daten ID, Benutzername, Passwort, Token und Zeit. Diese lange Folge von Passwörtern wird aufgrund der Hash-Verschlüsselung zusammengestellt.
Fügen Sie nach der Formularvalidierung in register.vue den folgenden Code hinzu
//register.vue
if (valid) {
axios.userRegister(this.ruleForm)
.then(({}) => {
if (data.success) {
this.$message({
type: 'success',
message: '注册成功'
});
} else {
this.$message({
type: 'info',
message: '用户名已经存在'
});
}
})
}
Wir haben zuvor in der Anmeldekomponente keine Daten übermittelt. Jetzt fügen wir eine Reihe von Methoden hinzu, um den Anmeldevorgang nach erfolgreicher Überprüfung abzuschließen: Wir stellen Axios vor
import axios from '../axios.js'
Fügen Sie dann nach der Formularüberprüfung in login.vue den folgenden Code hinzu
//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');
}
});
}
Senden Sie die Formulardaten an den Hintergrund, geben Sie den Datenstatus zurück und ermitteln Sie, ob das Konto vorhanden ist oder nicht. Nach erfolgreicher Anmeldung müssen Sie das zurückgegebene Token und den Benutzernamen abrufen, diese im Store speichern und zur HelloWorld-Zielseite springen.
Nach erfolgreicher Registrierung und Anmeldung sind wir endlich auf der eigentlichen Anzeigeseite angekommen – helloworld!
Lassen Sie uns diese Komponente verbessern, sodass sie alle derzeit registrierten Benutzernamen anzeigt und eine Schaltfläche zum Löschen enthält.
//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>
Die Ausgabeseite ist relativ einfach. Hier sind einige wichtige Punkte:
1. Die getUser()-Schnittstelle muss unmittelbar nach der Erstellung der Instanz angefordert werden ( created() ). Wenn die Anforderung fehlschlägt, muss das Token gelöscht werden. Wenn die Anforderung erfolgreich ist, müssen die Rückgabedaten in die Benutzerseite eingegeben werden Rendern.
2. Diese ID muss im Objektformat geschrieben werden, andernfalls wird ein Fehler gemeldet
3. Löschen Sie das Token beim Abmelden
Das Umdenken der Menschen zu ändern, ist in der Tat das Schwierigste. Gemäß dem Prozess sollte koa zuerst die Schnittstelle entwerfen, und dann wird das Front-End Anfragen basierend auf dieser Schnittstelle stellen. Umgekehrt schreibe ich jedoch zuerst die Front-End-Anfragen und formuliere dann die Schnittstelle basierend auf dieser Anfrage.
Natürlich bin ich auch auf viele Schwierigkeiten gestoßen: Als ich die Front-End-Anzeigeseite fertiggestellt und Axios geschrieben hatte, hatte ich keine Ahnung, wie ich die Benutzeroberfläche mit Koa schreiben wollte „Ich weiß nur, wie man die Daten eingibt, nicht, wie man sie wieder herausbekommt.“ Dann bin ich auf einen Schnittstellenfehler von 500 gestoßen und habe ihn lange debuggt. Der Hauptgrund war, dass ich keine Ahnung hatte, wie man die Schnittstelle debuggt. Am Ende hat mir der Chef des Unternehmens geholfen, das Problem zu lösen.