Hace algún tiempo, estaba hablando de su trayectoria profesional con un colega de la empresa que había pasado de la tecnología al producto y dijo algo en lo que yo creía profundamente:
"No se limite a un campo determinado. La transformación de la tecnología al producto es, ante todo, un cambio de mentalidad. Usted ha estado trabajando en el front-end. Al interactuar con los datos, sólo sabe cómo ingresarlos, pero No sé cómo sale. Esto es una limitación”.
Fue como una iluminación. Cuando estaba aprendiendo Vue, vi un proyecto de registro e inicio de sesión. Simplemente hice lo mismo y comencé un proyecto de Vue, introduje koa y mongodb e implementé todo el proceso de envío-servidor de entrada de base de datos. .
Este proyecto está construido en base a vue-cli, utiliza el método token para verificar el inicio de sesión del usuario e implementa funciones como registrarse en la base de datos, leer usuarios y eliminar usuarios. El artículo supone que los lectores tienen cierta base en nodos y vue, por lo que las partes básicas no se describirán en detalle.
Entorno del sistema: MacOS 10.13.3
Instalar usando el espejo Taobao
$ npm install -g cnpm --registry=https://registry.npm.taobao.org
Luego cambie toda la instalación de npm a instalación de cnpm
Para aclarar las ideas del proyecto y las tecnologías seleccionadas, se dibuja un diagrama para facilitar su comprensión.
1.Inicializar el proyecto
$ npm install
2. Iniciar el proyecto
$ npm run dev
3. Inicie MongoDB
$ mongod --dbpath XXX
xxx es la ruta a la carpeta de datos en el proyecto (también puede crear una nueva, la base de datos se usa para almacenar datos), o puede arrastrarla directamente a la terminal.
4. Inicie el servidor
$ node server.js
Elegí Element-UI de Ele.me como mi biblioteca de UI preferida para vue. Otras como iview y vue-strap no parecen ser tan completas como ele.
$ npm i element-ui -S
//在项目里的mian.js里增加下列代码
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
Utilice el cambio de pestaña en la interfaz de usuario para cambiar entre las interfaces de registro e inicio de sesión, utilice el componente de inicio de sesión como la interfaz principal de todo el sistema de inicio de sesión y el componente de registro como un componente independiente. Consulte el sitio web oficial para conocer el método de composición de Element-UI, la validación de formularios y otras API.
//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>
Lo siguiente es registrar el componente.
//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 es el núcleo de Vue para crear proyectos de una sola página. Las aplicaciones se pueden componer combinando componentes. Lo que tenemos que hacer es asignar componentes a rutas y luego decirle a vue-router dónde renderizarlos. El código anterior ya implica algunos cambios de enrutamiento. Mejoremos el enrutamiento ahora:
$ cnpm i vue-router
import Router from 'vue-router'
Vue.use(Router)
Cree un nuevo enrutador (carpeta)/index.js en la carpeta src. Hemos introducido tres componentes:
Página de visualización de HelloWorld después de iniciar sesión
iniciar sesión iniciar sesión en la interfaz principal
componente de registro de registro
Utilice router.beforeEach protección de enrutamiento para configurar la página en la que se debe iniciar sesión primero. Utilice el campo requireAuth para determinar si la ruta requiere permisos de inicio de sesión. Las rutas que requieren permisos serán interceptadas y luego se determinará si hay un token (el token se discutirá a continuación). saltar a la página de inicio de sesión.
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;
Podemos ver que el token en la protección de enrutamiento se obtiene de la tienda, lo que significa que almacenamos los distintos estados del token en la tienda y realizamos operaciones como recuperación, actualización y eliminación. Esto requiere la introducción de la gestión de estado de vuex. .
Explique por qué una página simple de registro e inicio de sesión requiere el uso de vuex: la operación de cada uno de nuestros componentes en el proyecto básicamente requiere obtener un token para verificación. Si el componente A almacena un token, la adquisición del token por parte del componente B implica la comunicación del componente. lo cual sería muy tedioso. Con la introducción de vuex, ya no es la comunicación entre componentes, sino la comunicación entre los componentes y la tienda, lo que es simple y conveniente.
$ cnpm i vuex --S
Introduzca store en main.js y agregue store a la instancia de vue.
//引入store
import store from './store'
Luego introdúzcalo en los componentes que necesitan usar vuex.
//store index.js
import Vuex from 'vuex'
Vue.use(Vuex)
Cree una nueva tienda (carpeta)/index.js en la carpeta 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
});
Puede ver que enviamos mutaciones a través de acciones, cambiamos tokens, borramos tokens y almacenamos nombres de usuario.
Cuando inicie el proyecto en este momento, podrá ver la interfaz preliminar de registro e inicio de sesión. Haga clic en el botón de registro o inicio de sesión para cambiar a la interfaz correspondiente y, después de iniciar sesión, accederá a la página de helloworld.
Hemos escrito la interfaz básica y el siguiente paso es enviar los datos del formulario a un segundo plano y realizar una serie de procesamientos. No importa si todavía no hay una interfaz de back-end. Primero escribamos la solicitud de axios de front-end.
La comunicación de Vue utilizaba vue-resource antes y había muchos obstáculos. Hasta que llegue vue2.0, simplemente abandone vue-resource y use axios .
Encapsula ajax, utilizado para enviar solicitudes y obtener datos de forma asincrónica. Cliente HTTP basado en promesas, adecuado para: navegador y node.js.
Descripción de API específica en chino: https://www.kancloud.cn/yunye/axios/234845
$ cnpm i -S axios
import axios from 'axios'
En la parte de configuración de vue-router, se agregan protectores de enrutamiento para interceptar rutas que requieren inicio de sesión, pero este método es solo un simple control de enrutamiento frontal y realmente no puede impedir que los usuarios accedan a rutas que requieren permisos de inicio de sesión. Cuando el token caduca, aún se guarda localmente. En este momento, cuando accede a una ruta que requiere permisos de inicio de sesión, debería pedirle al usuario que inicie sesión nuevamente. En este momento, se necesitan interceptores + el código de estado http devuelto por la interfaz de backend para juzgar.
Cree un nuevo axios.js en la carpeta src (mismo nivel que 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);
}
}
El código finalmente expone cuatro métodos de solicitud, que corresponden a registrar, iniciar sesión, obtener (usuario) y eliminar (delUser), y todos están en /api. Las cuatro interfaces de solicitud son:
http://localhost:8080/api/login
http://localhost:8080/api/register
http://localhost:8080/api/user
http://localhost:8080/api/delUser
Más adelante usaremos estos cuatro métodos para escribir la interfaz de backend correspondiente.
El artículo comienza desde aquí en el lado del servidor. Dado que el lado del servidor debe construirse junto con la base de datos y la comunicación segura http (jwt), lea esta sección junto con los capítulos sobre la base de datos y jwt a continuación.
koa2 puede usar la sintaxis async/await para evitar el engorroso y repetido anidamiento de funciones de devolución de llamadas, y usar ctx para acceder al objeto Context.
Ahora usamos koa2 para escribir la interfaz de servicio API del proyecto.
$ cnpm i koa
$ cnpm i koa-router -S //koa路由中间件
$ cnpm i koa-bodyparser -S //处理post请求,并把koa2上下文的表单数据解析到ctx.request.body中
const Koa = require('koa');
Cree un nuevo server.js en el directorio raíz del proyecto como entrada de inicio para todo el servidor.
//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);
});
Como se puede ver en el código, tanto la obtención como la eliminación de usuarios requieren tokens de verificación (consulte el capítulo jwt a continuación para obtener más detalles), y hemos colgado las cuatro interfaces en /api, lo cual es consistente con la ruta de solicitud anterior de axios.
Además, dado que el puerto de inicio de nuestro proyecto es 8080 y el puerto monitoreado por la interfaz koa es 8888, debemos agregar lo siguiente a la configuración de desarrollo en el archivo config/index.js:
proxyTable: {
'/api': {
target: 'http://localhost:8888',
changeOrigin: true
}
},
JWT puede ayudarnos a realizar la autenticación de identidad durante la comunicación HTTP.
Para obtener detalles específicos de la API, consulte: https://segmentfault.com/a/1190000009494020
1. El cliente inicia sesión en el servidor mediante nombre de usuario y contraseña;
2. El servidor verifica la identidad del cliente;
3. El servidor genera un Token para el usuario y lo devuelve al cliente;
4. El cliente guarda el token en el navegador local, generalmente en una cookie (este artículo usa sessionStorage, depende de la situación);
5. Cuando el cliente inicia una solicitud, debe llevar el Token;
6. Después de recibir la solicitud, el servidor primero verifica el Token y luego devuelve los datos. El servidor no necesita guardar el Token, solo necesita verificar la información contenida en el Token. No importa a qué servidor acceda el cliente en segundo plano, siempre que pueda pasar la verificación de la información del usuario.
En la carpeta del servidor, cree una nueva /token (carpeta) a continuación y agregue checkToken.js y createToken.js para colocar métodos para verificar y agregar tokens respectivamente.
$ 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;
};
Al crear el token, usamos el nombre de usuario como atributo de la carga útil JWT, configuramos la clave en 'zhangzhongjie' y establecemos el tiempo de vencimiento del token en 60 segundos. Esto significa que después de iniciar sesión, actualizar la página dentro de los 60 segundos no requiere iniciar sesión nuevamente.
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();
};
Obtenga el token primero y luego use jwt.verify para verificarlo. Tenga en cuenta que la clave debe corresponder a la clave 'zhangzhongjie' de createToken.js. Si el token está vacío, caduca o no pasa la verificación, se generará un error 401 que le solicitará que inicie sesión nuevamente.
MongoDB es un sistema de gestión de bases de datos orientado a documentos diseñado para proporcionar soluciones de almacenamiento de datos escalables y de alto rendimiento para aplicaciones WEB. Es muy conveniente utilizar node para conectarse a MongoDB.
$ cnpm i mongoose -S
Hay varias formas de conectarse a MongoDB. Aquí usamos la conexión. conexión es la referencia predeterminada del módulo mangosta y devuelve un objeto Conexión.
Cree un nuevo db.js en la carpeta del servidor como entrada de conexión de la base de datos.
//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;
Además de la conexión que utilizamos, también existen los métodos de conexión *connect() y createConnection()*.
Schema define la plantilla de la tabla para que este tipo de documento tenga una composición y modo de almacenamiento específico en la base de datos. Pero solo define cómo se ve el documento. En cuanto a generar el documento y realizar varias operaciones en el documento (agregar, eliminar, modificar y verificar), se realiza a través del modelo correspondiente. Luego, necesitamos convertir el esquema de usuario en algo. podemos usar. modelo, es decir, el modelo es el identificador sobre el que podemos operar.
Después de compilar el modelo, obtenemos un modelo llamado Usuario .
Preste atención a la tabla de esquema que define aquí. El almacenamiento de datos debe corresponder a esta tabla cuando la escriba y registre en la base de datos más adelante.
Cree un nuevo controlador (carpeta)/user.js en la carpeta del servidor para almacenar los métodos de operación de la base de datos.
Instale algunos complementos funcionales primero
$ 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
};
Los métodos anteriores forman el núcleo de las operaciones de la base de datos en el proyecto. Analicémoslos.
Primero, se definen tres métodos básicos comunes: findUser, findAllUsers y delUser. Entre ellos, findUser debe pasar el parámetro de nombre de usuario y delUser debe pasar el parámetro de identificación .
Obtenga la información del formulario enviada por la publicación del usuario, el nuevo usuario que fue diseñado previamente de acuerdo con la base de datos y compilado en un modelo, y el nombre de usuario obtenido, la contraseña (debe cifrarse con el hash sha1), el token (usando el nombre creado previamente). método createToken y utilice el nombre de usuario como parámetro de carga útil de jwt) y ahorre tiempo de generación.
En este momento, primero debe buscar en la base de datos para ver si el nombre de usuario existe. Si existe, devolverá un error. De lo contrario, el usuario se almacenará en la base de datos y se devolverá el éxito.
Obtenga la información del formulario de la publicación, el nombre de usuario y la contraseña del usuario (el registro tiene un hash y debe descifrarse en este momento). Busque el nombre de usuario en la base de datos para determinar si el nombre de usuario existe. Si no hay error de devolución, determine si la contraseña almacenada en la base de datos es consistente con la contraseña enviada por el usuario. Si son consistentes, se generará un nuevo token. el usuario y almacenado en la base de datos. Devolución exitosa.
Simplemente encapsule el método público findAllUsers anterior y coloque la información en el resultado, para que la página helloworld pueda obtener estos datos y mostrarlos más tarde.
Tenga en cuenta que primero debe obtener la ID de usuario que debe eliminarse y pasarla como parámetro.
Después de escribir estos métodos, puede mejorar las funciones de registro e inicio de sesión que antes no eran perfectas.
Cuando completamos el registro y los datos se almacenan en la base de datos, queremos verificar los datos recién registrados y almacenados en la base de datos, y necesitamos usar herramientas de visualización de bases de datos. Yo uso MongoBooster , que es fácil de operar.
Como puede ver en la figura siguiente, los dos datos registrados en el ejemplo incluyen identificación, nombre de usuario, contraseña, token y hora. Esa larga cadena de contraseñas se compila gracias al cifrado hash.
Agregue el siguiente código después de la validación del formulario en 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: '用户名已经存在'
});
}
})
}
Antes no enviamos ningún dato en el componente de inicio de sesión. Ahora agregamos una serie de métodos para completar la operación de inicio de sesión después de una verificación exitosa: Presentación de axios.
import axios from '../axios.js'
Luego agregue el siguiente código después de la verificación del formulario en 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');
}
});
}
Envíe los datos del formulario a un segundo plano, devuelva el estado de los datos y determine si la cuenta existe o no. Después de iniciar sesión correctamente, debe obtener el token y el nombre de usuario devueltos, guardarlos en la tienda y saltar a la página HelloWorld de destino.
Después de registrarnos e iniciar sesión con éxito, finalmente llegamos a la página de visualización real: ¡hola mundo!
Mejoremos este componente para que muestre todos los nombres de usuarios registrados actualmente y tenga un botón de eliminación.
//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>
La página de salida es relativamente simple. Aquí hay algunos puntos clave:
1. La interfaz getUser() debe solicitarse inmediatamente después de crear la instancia ( created() ). Si la solicitud falla, el token debe borrarse. Si la solicitud tiene éxito, los datos devueltos deben ingresarse en la página de usuario. representación.
2. este ID debe escribirse en formato de objeto; de lo contrario, se informará un error
3. Borre el token al cerrar sesión.
De hecho, cambiar la forma de pensar de la gente es lo más difícil. Según el proceso, koa debe diseñar la interfaz primero y luego el front-end realizará solicitudes basadas en esta interfaz, pero a la inversa, primero escribo las solicitudes del front-end y luego formulo la interfaz en función de esta solicitud.
Por supuesto, también encontré muchas dificultades: cuando terminé la página de visualización frontal y escribí axios, estuve atascado durante mucho tiempo usando koa para escribir la interfaz. Como se mencionó en el prefacio. "Sólo sé cómo ingresar los datos, no cómo ingresarlos". Luego encontré un error de interfaz de 500 y lo depuré durante mucho tiempo. La razón principal fue que no tenía idea de depurar la interfaz. Al final, el jefe de la empresa, Langya, ayudó a resolver el problema.