18.注册和登录


准备

技术栈

node,express, nodemon,bcrypt,joi

1.注册

(1)添加注册路由及注册页面展示

//用户注册页面
router.get('/admin/register', (req, res) => {
    const {
        message
    } = req.query
    res.render("admin/user-edit.html", {
        message
    })
})

(2)视图层设置form提交数据,服务端得到数据

      <form class="form-container" method="post" action="/admin/register">
            <div class="form-group">
                <label>用户名</label>
                <input type="text" name="username" class="form-control" placeholder="请输入用户名">
            </div>
            <div class="form-group">
                <label>邮箱</label>
                <input type="email" name="email" class="form-control" placeholder="请输入邮箱地址">
            </div>
            <div class="form-group">
                <label>密码</label>
                <input type="password" name="password" class="form-control" placeholder="请输入密码">
            </div>
            <div class="form-group">
                <label>角色</label>
                <select class="form-control" name="role">
                    <option value="normal">普通用户</option>
                    <option value="admin">超级管理员</option>
                </select>
            </div>
            <div class="form-group">
                <label>状态</label>
                <select class="form-control" name="state">
                    <option value="0">启用</option>
                    <option value="1">禁用</option>
                </select>
            </div>
            <div class="buttons">
                <input type="submit" class="btn btn-primary">
            </div>
        </form>

(3)视图层验证。 视图层验证表单内容是否填写

//1.表单序列化
function serializeToJson(form) {
    var result={}
    var f = form.serializeArray()
    f.forEach(function (item) {
        result[item.name] = item.value
    })
    return result
}


//2.判断表单字段
    var result = serializeToJson(Form)//序列化获取表单
       if (result.email.trim().length == 0) {
            alert("请输入邮箱")
            // 阻止表单默认提交
            return false
        }

(4)服务端验证。

  • 验证表单内容是否符合格式 使用第三方模块 joi
    const schema = joi.object({
        username: joi.string().min(3).max(20).required().error(new Error("用户名设置错误")),
        password: joi.string().pattern(new RegExp('^[a-zA-Z0-9]{3,30}$')).required().error(new Error("密码设置错误")),
        email: joi.string().required().email({
            minDomainSegments: 2,
            tlds: {
                allow: ['com', 'net']
            }
        }),
        role: joi.string().valid('normal', 'admin').required().error(new Error("角色值设置错误")),
        state: joi.number().valid(0, 1).required().error(new Error("状态值设置错误")),
    })

    try { //验证通过执行
        // 实现验证
        await schema.validateAsync(req.body)

    } catch (e) { // 验证错误执行
        //重定向到编辑页,并将错误信息传过去
        return res.redirect(`/admin/register?message=${e.message}`)
    }


  • 验证注册的邮箱地址是否注册过,使用mongoose查询方法
    // 2.验证用户(使用邮箱)是否被注册.如果找得到email说明数据库存在,否则不存在,不存在就实行添加
    let user = await User.findOne({
        email: req.body.email
    })
    if (user) { //查询到了,则不能注册,重定向到注册页面
        return res.redirect(`/admin/register?message=邮箱已被注册`)
    }

(5)密码加密技术bcrypt

    // 3.对密码加密
    // 3.1生成随机字符串
    const salt = await bcrypt.genSalt(10)
    // 3.2 加密替换代码
    req.body.password = await bcrypt.hash(req.body.password, salt)

(6)将信息添加到数据库

    await new User(req.body).save()
    //或者 
	//await User.create(req.body)

(7)重定向到用户页面

 res.redirect('/admin/user')

2.登录

(1)创建用户集合,登录用户

  • 连接数据库
  • 创建用户集合
  • 初始化用户

user.js

// 创建用户集合
var mongoose = require('mongoose')
//2.连接并创建数据库
mongoose.connect("mongodb://localhost/blog").then(() => {
    console.log('连接成功');
}).catch(() => {
    console.log('连接失败');
})
const Schema = mongoose.Schema
var userSchema = new Schema({
    username: {
        type: String,
        required: true, //用户必须
        minlength: 2,
        maxlength: 20
    },
    email: {
        type: String,
        unique: true, //保证唯一性(不重复)
    },
    password: {
        type: String,
        required: true
    },
    role: { //admin超级管理员
        type: String,
        required: true
    },
    state: { //0为启用,1为禁用
        type: Number,
        default: 0
    }

})


// 插入数据检测(初始化用户)
// User.create({
//     username:'admin',
//     email:'333@qq.com',
//     password:'admin',
//     role:'admin',
//     state:0
// }).then(()=>{
//     console.log('创建成功');
// }).catch(()=>{
//     console.log('创建失败');
// })
//将用户集合作为模块成员导出
// 实例化文档结构(将文档结构发布为模型)
module.exports = mongoose.model('User', userSchema)

(2)视图层设置form提交数据

login.html

     <form id="loginForm" action="/login" method="post">
                    <div class="form-group">
                        <label>邮件</label>
                        <input type="email" name="email" class="form-control" placeholder="请输入邮件地址">
                    </div>
                    <div class="form-group">
                        <label>密码</label>
                        <input type="password" name="password" class="form-control" placeholder="请输入密码">
                    </div>
                    <button type="submit" class="btn btn-primary loginForm">登录</button>
                </form>

(3)视图层验证。 视图层验证表单内容是否填写,如果没填写完整则阻止登录

视图层js文件

//1.表单序列化
function serializeToJson(form) {
    var result={}
    var f = form.serializeArray()
    f.forEach(function (item) {
        result[item.name] = item.value
    })
    return result
}


//2.判断表单字段
    var result = serializeToJson(Form)//序列化获取表单
       if (result.email.trim().length == 0) {
            alert("请输入邮箱")
            // 阻止表单默认提交
            return false
        }

(4)服务端验证。

  • 验证邮箱和密码是否输入(错误状态码400)
  • 服务器接收数据,验证表单内容是否填写,如果没填写完整则阻止登录

(4.1)创建登录路由页面

router.get('/login', function (req, res) {
    // res.status(200).send("后台管理页面")
    // res.send("后台管理页面")
    res.render("admin/login.html")
})

(4.2)登录功能操作

router.post('/login', async (req, res) => {

    const {
        email,
        password
    } = req.body //解构语法,把对象中的req.body.email的值赋值给了email,把对象中的req.body.password的值赋值给了password


    // res.send('ok')
    // 1.验证用户是否输入了邮箱和密码(验证form表单传过来的数据是否存在)
    if (email.trim().length == 0 || password.trim().length == 0)
        return res.status(400).render("admin/err.html", {
            msg: '邮箱或者密码错误'
        }) //状态码400 请求信息有问题

    // 2.根据邮箱地址查询用户信息是否存在
    // 查询到用户,则user表中有对象,否则为空
    let user = await User.findOne({
        email
    })
    if (user) { //查询到了
        // 将form传递的密码和数据库中的进行比对
		 let isValid = await bcrypt.compare(password, user.password)
        if (isValid) {
            req.session.username=user.username //将用户名存储到session对象
            // res.send('登录成功')
            req.app.locals.userInfo=user;//将用户信息存放到模板 req.app.locals.名称=变量
            res.redirect('/user')
        } else {
            res.status(400).render("admin/err.html", {
                msg: '邮箱或者密码错误'
            }) //状态码400 请求信息有问题
        }
    } else { //没查询到
        res.status(400).render("admin/err.html", {
            msg: '邮箱或者密码错误'
        }) //状态码400 请求信息有问题
    }
})

此处注意:需要另外希望一个err.html文件来显示错误页面

(5)密码比对成功才能登录(密码加密技术bcrypt)

 let isValid = await bcrypt.compare(password, user.password)

(6)cookie与session

  • 设置session

app.js

const session = require('express-session') //导入express-session
//配置session
app.use(session({
    secret: 'secret:key',
    saveUninitialized:false,//退出登录不会存储cookie
    cookie:{
        maxAge:24*60*60*1000    //设置cookie过期时间为一天,如果不设置浏览器关闭则登录状态失效
    }
}))
  • 使用session
   req.session.username = user.username //将用户名存储到session对象

(7)用户退出

点击用户退出按钮删除cookie,重定向到登录页面

//3.用户登录退出
router.get("/admin/logout", (req, res) => {
    //删除cookie
    req.session.destroy(function () {
        //删除Cookie
        res.clearCookie('connect.sid') // res.clearCookie(cookie名称)
        //重定向到登录
        res.redirect('/admin/login')
    })
    //删除session
    //重定向到登录页面
})

(8)登录拦截

  • 1.判断是否为登录页面

当页面不是登录的页面,使用拦截器将页面重定向到登录页面

  • 2.判断是否为登录状态

判断session是否存在来判断是否为登录状态

//拦截器,拦截登录状态
router.use('/admin', (req, res, next) => {
    //1.判断用户是否是登录页面
    // 2.判断用户登录状态
    //如果登录,将请求放行
    //如果未登录,重定向到登录
    if (req.url != "/login" && !req.session.username) { //如果未登录,重定向到登录
        res.redirect("/admin/login")
    } else { //如果登录,将请求放行

        next()
    }
})

代码


register.js

const express = require('express')
const User = require('../../model/user') //user数据表
const joi = require('joi')
const bcrypt = require('bcrypt')
let router = express.Router() //创建router
//用户首页
router.get('/admin/user', (req, res) => {
    res.render("admin/user.html", {
        msg: req.session.username
    })
})

//用户注册页面
router.get('/admin/register', (req, res) => {
    const {
        message
    } = req.query
    res.render("admin/user-edit.html", {
        message
    })
})

// 用户注册处理
router.post('/admin/register', async (req, res) => {
    // 1.验证表单内容是否符合格式 
    //创建验证规则
    const schema = joi.object({
        username: joi.string().min(3).max(20).required().error(new Error("用户名设置错误")),
        password: joi.string().pattern(new RegExp('^[a-zA-Z0-9]{3,30}$')).required().error(new Error("密码设置错误")),
        email: joi.string().required().email({
            minDomainSegments: 2,
            tlds: {
                allow: ['com', 'net']
            }
        }),
        role: joi.string().valid('normal', 'admin').required().error(new Error("角色值设置错误")),
        state: joi.number().valid(0, 1).required().error(new Error("状态值设置错误")),
    })

    try { //验证通过执行
        // 实现验证
        await schema.validateAsync(req.body)

    } catch (e) { // 验证错误执行
        //重定向到编辑页,并将错误信息传过去
        return res.redirect(`/admin/register?message=${e.message}`)
    }

    // 2.验证用户(使用邮箱)是否被注册.如果找得到email说明数据库存在,否则不存在,不存在就实行添加
    let user = await User.findOne({
        email: req.body.email
    })
    if (user) { //查询到了,则不能注册,重定向到注册页面
        return res.redirect(`/admin/register?message=邮箱已被注册`)
    }
    // 3.对密码加密
    // 3.1生成随机字符串
    const salt = await bcrypt.genSalt(10)
    // 3.2 加密替换代码
    req.body.password = await bcrypt.hash(req.body.password, salt)
    // 3.3
    // req.body.password=password
    //4.增加信息
    await new User(req.body).save()
    // await User.create(req.body)
    res.redirect('/admin/user')
})


//404页面
router.use('/', (req, res, next) => {
    res.send('404')
})
module.exports = router //导出模块

login.js

const express = require('express')
const User = require('../../model/user') //user数据表
const bcrypt = require('bcrypt')
let router = express.Router() //创建router
//路由
//拦截器,拦截登录状态
router.use('/admin', (req, res, next) => {
    //1.判断用户是否是登录页面
    // 2.判断用户登录状态
    //如果登录,将请求放行
    //如果未登录,重定向到登录
    if (req.url != "/login" && !req.session.username) { //如果未登录,重定向到登录
        res.redirect("/admin/login")
    } else { //如果登录,将请求放行

        next()
    }
})
// 1.登录页面
router.get('/admin/login', function (req, res) {
    // res.status(200).send("后台管理页面")
    // res.send("后台管理页面")
    res.render("admin/login.html")
})

// 2.登录功能实现
router.post('/admin/login', async (req, res) => {

    const {
        email,
        password
    } = req.body //解构语法,把对象中的req.body.email的值赋值给了email,把对象中的req.body.password的值赋值给了password


    // res.send('ok')
    // 1.验证用户是否输入了邮箱和密码(验证form表单传过来的数据是否存在)
    if (email.trim().length == 0 || password.trim().length == 0)
        return res.status(400).render("admin/err.html", {
            msg: '邮箱或者密码错误'
        }) //状态码400 请求信息有问题

    // 2.根据邮箱地址查询用户信息是否存在
    // 查询到用户,则user表中有对象,否则为空
    let user = await User.findOne({
        email
    })
    if (user) { //查询到了
        // 将form传递的密码和数据库中的进行比对

        let isValid = await bcrypt.compare(password, user.password)

        if (isValid) {
            req.session.username = user.username //将用户名存储到session对象
            // res.send('登录成功')
            req.app.locals.userInfo = user; //将用户信息存放到模板 req.app.locals.名称=变量
            res.redirect('/admin/user')
        } else {
            res.status(400).render("admin/err.html", {
                msg: '邮箱或者密码错误'
            }) //状态码400 请求信息有问题
        }
    } else { //没查询到
        res.status(400).render("admin/err.html", {
            msg: '邮箱或者密码错误'
        }) //状态码400 请求信息有问题
    }
})


//3.用户登录退出
router.get("/admin/logout", (req, res) => {
    //删除cookie
    req.session.destroy(function () {
        //删除Cookie
        res.clearCookie('connect.sid') // res.clearCookie(cookie名称)
        //重定向到登录
        res.redirect('/admin/login')
    })
    //删除session
    //重定向到登录页面
})

module.exports = router //导出模块


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM