无论是手机端还是pc端,几乎都包含登录注册方面功能,今天总结登录注册功能。
实现功能
注册 密码加密
登录 校验 token处理
1.环境搭建运行(node+express+mongodb)
在目录里安装express和mongoose,并在根目录创建server.js文件和models文件,
在server.js文件中
const express = require('express');
const app = express();app.listen(3001,() =>{console.log('http://localhost:3001')
})
在你models文件中链接MongoDB数据库,express-auth这个就是你数据库的名字,27017是你数据库的端口号,mongodb不需要打开数据库可视化工具,根据名字就自动创建这个数据库名了
const mongoose = require('mongoose')
// 链接数据库
mongoose.connect('mongodb://localhost:27017/express-auth',{useCreateIndex:true,useNewUrlParser:true
})
在你server.js写一点路由,测试数据库是否链接成功,启动服务的话,你可以全局安装nodemon ,然后通过在命令控制台出入nodemon server.js就可以,会实时更新我们修改的代码,
app.get('/api/test',async(req,res) =>{res.send('ok')
})
在这里我们可以在Vcode中安装一个REST Client插件,可以不需要postman就可以调试接口,也是在你的根目录创建一个http结尾的目录。url就是我们的访问域名,定义一个全局的,get就是请求方式,后面test就是请求名。在右边就可以看到我们返回的结果。要在server.js目录引入才能生效。
注册功能
首先建立模型,在models.js建立对应的模型,这里因为是登录和注册,就写两个字段就行,如果需要,可以自行添加对应的字段名,unique表示用户名是唯一的,不让重复添加
userModels.js
const mongoose = require('mongoose');
let userSchema = new mongoose.Schema({username: {type: String,unique:true},password: {type: String,set(val) {// 通过bcryptjs对密码加密返回值 第一个值返回值, 第二个密码强度//需要提前安装(npm install bcryptjs --save)return require('bcryptjs').hashSync(val, 10)}},});
let userModel = mongoose.model('user', userSchema);module.exports = userModel
在你user.js文件,先引入这个模型
var express = require('express');
var router = express.Router();
//创建token使用 (安装 npm i jsonwebtoken)
const jwt = require('jsonwebtoken')
const UserModel=require('../models/UserModels.js')
进行登录的验证,登录和注册用的字段一样的。所以不需要建立模型编写,登录时候,第一步肯定先判断用户是不是存在,如果用户不存在,直接返回状态码和错误信息,也不需要执行下一步,第二步用户名过了,接来下就是验证密码是否正确,通过compareSync验证面密码是否正确,如果正确就返回,不正确的话也是返回状态码和错误信息,最后一步就是生成token,返回客户端,客户端可以通过token判断是哪个用户。
//登录账号
router.post('/login',async(req,res) =>{//SECRET定义的是一个秘钥,先随便填写,这个秘钥应该不要出现在代码中,const SECRET = 'ewgfvwergvwsgw5454gsrgvsvsd'const user = await UserModel.findOne({username:req.body.username,})//如果用户名不存在if(!user){return res.status(422).json({code:'421',message:"用户不存在"})}//判断密码是否正确const isPasswordValid = require('bcryptjs').compareSync(req.body.password,user.password)console.log(isPasswordValid);if(!isPasswordValid){return res.status(422).json({code:'422',message:"密码无效"})}//添加tokenconst token = jwt.sign({id:String(user._id)},SECRET)// 生成tokenres.json({code: 20000,msg: '找到了',data:user,token:token})})
token校验
token校验,验证比如获取用户信息,发送什么东西的时候,判断token是否存在,如果存在可以执行,否则不能执行,全局写一个中间件,当每个接口使用的时候,直接调用就可以
const auth = async(req,res) =>{const raw = String(req.headers.authorization).split(' ').pop();// 验证const {id} = jwt.verify(raw,SECRET)req.user = await User.findById(id)
}
例如:请求用户列表,需要传token验证是否存在。auth就是验证这个token是否存在。
app.get('/api/profile',auth,async(req,res) =>{res.send(req.user)
})
至此后端部分完成,接下来实现前端登录。
2.前端登录(vue3)
2.1 创建utils文件夹
request.ts
import axios from 'axios'const http= axios.create({baseURL: '/api',// 通用请求地址前缀timeout: 10000,//超时时间
})// 添加请求拦截器
http.interceptors.request.use(function (config) {// 在发送请求之前做些什么return config;}, function (error) {// 对请求错误做些什么return Promise.reject(error);});// 添加响应拦截器
http.interceptors.response.use(function (response) {// 2xx 范围内的状态码都会触发该函数。// 对响应数据做点什么return response;}, function (error) {// 超出 2xx 范围的状态码都会触发该函数。// 对响应错误做点什么return Promise.reject(error);});
export default http
2.2 创建api文件夹,存放接口
user.js
import http from '../utils/request'//登录
export const getLogin= (data) =>{//返回一个promise对象return http.post('/login',data)
}
2.3 登录页面准备
静态资源页面
<template><div class="login"><div class="box"><el-form :model="ruleForm" :rules="rules" ref="ruleData" label-width="100px" class="demo-ruleForm"><h3>系统登录</h3><el-form-item label="账号" prop="username"><el-input placeholder="请输入账号" v-model="ruleForm.username"></el-input></el-form-item><el-form-item label="密码" prop="password"><el-input placeholder="请输入密码" type="password" v-model="ruleForm.password"></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></div></div>
</template>
<script setup>import { ref,reactive } from 'vue';import router from '../router';const ruleForm=reactive({username:'',password:'',})//定义表单校验规则const rules =reactive({username:[{required:true,massage:'请输入用户名',trigger:'blur'},{min:5,max:16,message:'请输入长度5~16非空字符',trigger:'blur'}],password:[{required:true,massage:'请输入密码',trigger:'blur'},{min:5,max:16,message:'请输入长度5~16非空字符',trigger:'blur'}],})const ruleData=ref(null)//重置信息const resetForm = () => {}
</script><style scoped >.login{display: flex;align-items: center;background: url(../../src/assets/images/2.jpg) no-repeat;background-size: 100%;width: 100vw;height: 100vh;}.box{margin: auto;padding: 40px;width: 500px;height: 320px;background-color: aliceblue;border-radius: 10px;box-sizing: border-box;}h3{color: #222;margin: auto;margin-bottom: 36px;text-align: center;}.el-button{margin-top: 20px;}
</style>
2.4 登录功能实现
引入依赖
import Cookies from 'js-cookie'import {getUsers,getLogin} from '../api/user.js'import { ElMessage } from 'element-plus'
登录功能
const submitForm = (ruleForm) => {ruleData.value.validate((valid) => {if (valid) {getLogin(ruleForm).then(({data}) => {console.log(data);if (data.code === 20000) {router.push('/article')//创建cookiesCookies.set('token', data.token)} else {ElMessage({message: '账号密码错误',type: 'error',})}})}})}
2.5 在router中添加路由守卫
// 全局守卫:登录拦截 本地没有存token,请重新登录
router.beforeEach((to, from, next) => {const token=Cookies.get('token')// 判断有没有登录if (!token) {if (to.name == "login") {next();} else {router.push('login')}} else {next();}
});