nodejs实现登录注册系统

nodejs实现登录注册系统

对上一次的功能进一步的完善,将用户的数据储存在本地数据库,实现登录的功能,采用session机制记录登录信息,使得已登录的用户保持登录状态


目录结构

目录结构比较简单,算是一个小的demo

nodejs实现登录注册系统_第1张图片

  • model是数据层,将采用mongoose创建数据库模型,并提供接口
  • public是静态资源,随http发送请求并加载
  • routes是控制层,包含路由控制和逻辑处理
  • views是视图层,主要有三个页面
  • signin是入口文件

数据处理

Mongoose是一个提供了MongoDB地相映射的Node.js库,创建一个数据库模型schema,并将其发布成为model,统一数据模型并能进行操作

var mongoose = require("mongoose");
mongoose.connect('mongodb://localhost/test');
var Schema = mongoose.Schema;
//骨架模版
var userSchema = new Schema({
    username   : String,
    password   : String,
    id    : String,
    phone : String,
    email  : String
})
var User = mongoose.model('User', userSchema);
module.exports = User;

路由控制

主要是由routes.js控制,注意要加载静态资源和对session的设置,注册中间件

var express = require('express')
var routes = require('./server')
var app = express();
var bodyParser = require('body-parser');
var session = require('express-session')
// 创建 application/x-www-form-urlencoded 编码解析
var urlencodedParser = bodyParser.urlencoded({ extended: false })


module.exports = function(app) {
     
    // 设置页面的跳转还有session的设置
    app.use(session({ secret: 'keyboard cat', cookie: { maxAge: 60000 }}))
    app.use('/',routes);
    app.use('/regist',routes);
    app.use('/logout',routes);
    app.use('/info',routes);
    app.use('/check', routes);
    app.use(express.static(__dirname + '/public'));
}

逻辑处理

路由的控制还是在server.js中对逻辑的处理,并选择渲染的页面

  • 通过引入express.Router(),对其中的具体方法和回调函数进行处理
  • 视图层的显示采用动态模板进行渲染,因此render进行页面渲染的时候也提供了必要的数据
  • 对于用户登录的和退出时通过请求req.session对登录状态进行标示
  • 处于安全性考虑,数据库直接存放用户的密码,进行加密后判断
router.get('/regist',function (req, res) {
     
    res.render('index.ejs', {
        errorInfo:'请输入信息'
    })
})
router.get('/',function(req, res) {
     
// 默认登录到index要判断扥估状态,已经登录的用户进入详情页面
    if (!req.session.logged_in) {
        Notlogin(req, res)
    } else {
        loggedIn(req, res)
    }
})
//退出登录的用户进入登录页面
router.get('/logout', function(req, res) {
     
    req.session.logged_in = 0;
    res.render('signin.ejs', {
        errorInfo:'请输入信息'
    })
})
//登录处理
router.post('/check', urlencodedParser, function (req, res) {
     
    console.log("check password");
    var testuser = {
        username:req.body.username,
        password:req.body.password,

    }
    //这里采用md5对密码进行加密后在储存到数据库当中
    var d = getMD5Password(testuser.password)
    console.log("加密的结果:(验证)"+d);
    testuser.password = d;
    //采用model的方法,已经提供了各种接口,查找数据库中是否有次用户的信息,对用户登录进行验证
    User.find(testuser, function (err, detail) {
     
        if (detail.length) {
            signinCheckSuccess(detail, req, res)
        } else {
            console.log("wrong!");
            errorInfo = "用户名不存在或密码错误";
            res.render('signin.ejs',{
                errorInfo:errorInfo
            })
        }
    })
})
//注册处理
router.post('/info', urlencodedParser, function(req, res) {
     
    console.log("Data from submit form");
    var user = new User({
        username:req.body.username,
        password:req.body.password,
        id:req.body.id,
        phone:req.body.phone,
        email:req.body.email
    })
    var d = getMD5Password(user.password);
    console.log("加密的结果:"+d);
    user.password = d;
    console.log(user);
    var flag = {one:1,two:1,three:1,four:1};
    errorInfo = "";
    //这里对数据进行验证,不能够有重复的数据
    checkDataRep(user, flag, req, res);
})

其他工具函数

主要针对是否有用户登录之后的一些逻辑的判断,以及对数据库查找的格式进行统一,处理回调函数

// 验证用户注册提交的表单,如果没有问题,则记录登录状态
function dealWithDataSubmited (user, flag, req, res) {
     
    if (!(flag.one&&flag.two&&flag.three&&flag.four)) {
        repreload(res);
    } else {
        req.session.username = user.username;
        req.session.logged_in = 1;
        user.save(function(err) {
     
            if (err) {
                console.log('保存失败');
                return;
            }
            console.log('保存成功');
        })
        console.log(user.username + " has been added");
        showInfo(user, res)
    }
}
// user的find方法采用json格式,因此将传进去的名字转化为json格式之后对数据库进行访问,并处理逻辑,渲染页面
function findJson(name, res) {
     
    var testUsername = {username:name};
    User.find(testUsername,function (err, userDetail) {
     
        if (userDetail.length == 0) {
            console.log(userDetail);
            res.render('index.ejs', {
                errorInfo:'请输入信息'
            });

        } else {
            console.log(userDetail);
            console.log("Load user: " + name);
            console.log(userDetail[0]);
            showInfo(userDetail[0], res);
        }
    })
}
// 对用户访问index页面的逻辑进行处理,主要是看url后面有没有附带信息
function Notlogin(req, res) {
     
    if (req.param("username") == undefined) {
        console.log("initial page");
        res.render('signin.ejs', {
            errorInfo:'请输入信息'
        })
    } else {
        var username = req.param("username").toString();
        console.log("find user: " +  username);
        findJson(username, res)
    }
}
// 如果已经有用户登录了就显示当前登录的用户
function loggedIn(req, res) {
     
    if (req.param("username") == undefined) {
        findJson(req.session.username, res);
    } else {
        var username = req.param("username").toString();
        console.log(username);
        // 不能显示非当前登录用户的信息
        if (username != req.session.username) {
            var testUsername = {username:req.session.username};
            User.find(testUsername,function (err, userDetail) {
     
                infoPage(res, userDetail, "只能显示已登录用户")
            })
        } else {
            var testUsername = {username:req.session.username};
            User.find(testUsername,function (err, userDetail) {
     
                infoPage(res, userDetail, "用户详情")
            })
        }
    }
}
function getMD5Password(content) {
     
    var md5 = crypto.createHash('md5');//定义加密方式:md5不可逆,此处的md5可以换成任意hash加密的方法名称;
    md5.update(content);
    var d = md5.digest('hex');  //加密后的值d
    return d;
}
// 处理数据,注意格式
function signinCheckSuccess(detail, req, res) {
     
    var userInDatabase = {
        username:detail[0].username,
        userId:detail[0].id,
        phone:detail[0].phone,
        email:detail[0].email
    }
    console.log("user in database :");
    console.log(userInDatabase);
    req.session.logged_in = 1;
    req.session.username = req.body.username;
    showInfo(userInDatabase, res);
}
function infoPage(res, userDetail, errorInfoDetail) {
     
    res.render('info.ejs', {
        username:userDetail[0].username,
        userId:userDetail[0].id,
        phone:userDetail[0].phone,
        email:userDetail[0].email,
        errorInfo:errorInfoDetail
    })
}
function showInfo(user, res) {
     
    res.render('info.ejs', {
        username:user.username,
        userId:user.id,
        phone:user.phone,
        email:user.email,
        errorInfo:'用户详情'
    });
}
function checkDataRep(user, flag, req, res) {
     
// 逐一验证储存的信息是否重复
    var testUsername = {username:user.username};
    var testId = {id:user.id};
    var testPhone = {phone:user.phone};
    var testEmail = {email:user.email};
    User.find(testUsername, function (err, detail) {
     
        if (detail.length) {
            flag.one = 0;
            errorInfo = errorInfo + "用户名重复\n";
        }
    })
    User.find(testId, function (err, detail) {
     
        if (detail.length) {
            flag.two = 0;
            errorInfo = errorInfo + "id重复\n";
        }
    })
    User.find(testPhone, function (err, detail) {
     
        if (detail.length) {
            flag.three = 0;
            errorInfo = errorInfo + "电话号码重复\n";
        }
    })
    User.find(testEmail, function (err, detail) {
     
        if (detail.length ) {
            flag.four = 0;
            errorInfo = errorInfo + "邮箱重复\n";
        }
        dealWithDataSubmited(user, flag, req, res)
    })
}
function repreload(res) {
     
    res.render('index.ejs',{
        errorInfo:errorInfo
    })
}

源码地址

github


总结

其实这一次的后端代码其中逻辑处理是比较复杂的,存在很大的优化空间,提高代码的可读性.而使用express框架和mongodb数据库模型的时候对一些api的时候来完成相应功能,是比较方便而且高效,其功能的强大远远不止于此。而对于项目的构建,可采用

express -e myapp

来生成目录,(-e表示ejs模板)

你可能感兴趣的:(web,nodejs)