无论是手机端还是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:"密码无效"
})
}
//添加token
const token = jwt.sign({
id:String(user._id)
},SECRET)
// 生成token
res.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')
//创建cookies
Cookies.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();
}
});