nodejs+pug——注册登录

1,943 阅读4分钟

之前写过用html写的页面,相关链接:nodeJs入门——注册及登录
基于之前的目录,改变view里面的页面文件
html 代码

node-demo/
|
+- controllers/ <-- Controller
|  |
|  +- login.js <-- 登录注册处理
|
+- views/ <-- html模板文件
|  |
|  +- head.pug <-- 头部css引入  
|  |
|  +- header.pug <-- js引入
|  |
|  +- layout.pug <-- 公共布局页面  
|  |
|  +- login.pug <-- 登录页面
|  |
|  +- signUp.pug <-- 注册页面
|  |
|  +- index.pug <-- 登陆完成主页  
|
+- public/ <-- 静态资源文件
|
+- models <-- models
|  |
|  +- db.js <-- 数据库连接池设置
|  |
|  +- dao_mysql.js <-- 数据库通用操作方法
|  |
|  +- query.js <-- 数据库查询
|
+- router <-- 路由文件
|  |
|  +- router.js <-- 路由配置
|
+- app.js <-- 入口文件
|
+- package.json <-- 项目描述文件
|
+- node_modules/ <-- npm安装的所有依赖包

首先,安装pug依赖包: npm install pug --save
然后将之前的页面改写为pug模板引擎
head.pug
javascript 代码

link(rel="stylesheet" href= CommonLibs +  '/css/bootstrap.css')
link(rel="stylesheet" href= CommonLibs +  '/css/font-awesome.css')
link(rel="stylesheet" href= CommonLibs +  '/css/style.css')

header.pug
javascript 代码

script(src= CommonLibs + '/js/jquery.js')
script(src= CommonLibs + '/js/popper.min.js')
script(src= CommonLibs + '/js/bootstrap.min.js')
script(src= CommonLibs + '/js/jQuery.md5.js')

layout.pug
javascript 代码

doctype
html
    head
        meta(charset='UTF-8')
        meta(http-equiv='X-UA-Compatible',content='IE=Edge,chrome=1')
        title #{title}
        block head
            include head
    body
        .containers
            nav.navbar.navbar-expand-md.navbar-dark.bg-dark
                a.navbar-brand(href='#')
                    i(class="fa fa-fort-awesome",aria-hidden="true")
                    |  Ghost Castle
                button(
                class="navbar-toggler"
                type="button"
                data-toggle="collapse"
                data-target="#navbarNavAltMarkup"
                aria-controls="navbarNavAltMarkup"
                aria-expanded="false"
                aria-label="Toggle navigation"
                )
                    span.navbar-toggler-icon
                div(class="collapse navbar-collapse justify-content-end" id="navbarNavAltMarkup")
                    .navbar-nav
                        block opration-content
            block content
        block header
            include header

login.pug
javascript 代码

extends layout
block prepend head
    link(rel="shortcut icon" href= CommonLibs + "/icons/glyph/si-glyph-castle.svg")
block opration-content
    a(class="nav-item nav-link active" href="#") Login
    a(class="nav-item nav-link" href="/register") Sign Up
block content
    .login.row.justify-content-md-center
        .col-md-8
            .card.border-secondary
                .card-header Login
                .card-body.text-secondary
                    form(id="login" onsubmit="return false;")
                        .form-group.row
                            lable(for="name" class="col-sm-4 text-right") Name
                            .col-sm-6
                                input(
                                type="text"
                                name="name"
                                class="form-control"
                                id="name"
                                placeholder="Name"
                                required
                                )
                        .form-group.row
                            lable(for="password" class="col-sm-4 text-right") Password
                            .col-sm-6
                                input(
                                type="password"
                                name="password"
                                class="form-control"
                                id="password"
                                placeholder="Password"
                                required
                                )
                        .form-group.row
                            lable.col-sm-4.text-right 验证码
                            #captcha.col-sm-6
                                p#wait.show 正在加载验证码......
                        .form-group.row
                            .col-sm-8.ml-sm-auto
                                label.custom-control.custom-checkbox.mb-2.mr-sm-2.mb-sm-0
                                    input(type="checkbox" class="custom-control-input")
                                    span.custom-control-indicator
                                    span.custom-control-description Remember me
                        .row
                            .col-sm-8.ml-sm-auto
                                button(type="submit" class="btn btn-dark" id="loginBtn")
                                    i(class="fa fa-sign-in" aria-hidden="true")
                                    |  LOGIN
append header
    script(src= CommonLibs + '/js/gt.js')
    script.
        function login(captchaObj) {
            var result = captchaObj.getValidate();
            if (!result) {
                return alert('请完成验证');
            }
            var name = $('input[name=name]').val();
            var pwd = $('input[name=password]').val();
            $.ajax({
                url: 'gt/validate-slide',
                type: 'POST',
                dataType: 'json',
                data: {
                    name: name,
                    password: $.md5(pwd),
                    geetest_challenge: result.geetest_challenge,
                    geetest_validate: result.geetest_validate,
                    geetest_seccode: result.geetest_seccode
                },
                success: function (data) {
                    if (data.result) {
                        alert('登录成功');
                        window.location.href = '/';
                    } else {
                        alert(data.errorMsg);
                        captchaObj.reset();
                    }
                }
            });
            return false;
        }
        var handler = function (captchaObj) {
            captchaObj.appendTo('#captcha');
            captchaObj.onReady(function () {
                $("#wait").hide();
            });
            $('#loginBtn').click(function () {
                login(captchaObj);
            });
            // 更多接口说明请参见:http://docs.geetest.com/install/client/web-front/
            window.gt = captchaObj;
        };


        $.ajax({
            url: "gt/register-slide?t=" + (new Date()).getTime(), // 加随机数防止缓存
            type: "get",
            dataType: "json",
            success: function (data) {

                // 调用 initGeetest 进行初始化
                // 参数1:配置参数
                // 参数2:回调,回调的第一个参数验证码对象,之后可以使用它调用相应的接口
                initGeetest({
                    // 以下 4 个配置参数为必须,不能缺少
                    gt: data.gt,
                    challenge: data.challenge,
                    offline: !data.success, // 表示用户后台检测极验服务器是否宕机
                    new_captcha: data.new_captcha, // 用于宕机时表示是新验证码的宕机

                    product: "float", // 产品形式,包括:float,popup
                    width: "100%"
                    // 更多配置参数说明请参见:http://docs.geetest.com/install/client/web-front/
                }, handler);
            }
        });

signUp.pug
javascript 代码

extends layout
block opration-content
    a(class="nav-item nav-link" href="/login") Login
    a(class="nav-item nav-link active" href="#") Sign Up
block content
    .login.row.justify-content-md-center
        .col-md-8
            .card.border-secondary
                .card-header Register
                .card-body.text-secondary
                    form(onsubmit="return false;")
                        .form-group.row
                            lable(for="name" class="col-sm-4 text-right") Name
                            .col-sm-6
                                input(
                                type="text"
                                name="name"
                                class="form-control"
                                id="name"
                                placeholder="Name"
                                required
                                )
                        .form-group.row
                            lable(for="sex" class="col-sm-4 text-right") Sex
                            .col-sm-6
                                label.custom-control.custom-radio
                                    input(
                                    id="radioStacked1"
                                    name="sex"
                                    type="radio"
                                    value="0"
                                    class="custom-control-input"
                                    required
                                    )
                                    span.custom-control-indicator
                                    span.custom-control-description Male
                                label.custom-control.custom-radio
                                    input(
                                    id="radioStacked2"
                                    name="sex"
                                    type="radio"
                                    value="1"
                                    class="custom-control-input"
                                    required
                                    )
                                    span.custom-control-indicator
                                    span.custom-control-description Female
                        .form-group.row
                            lable(for="address" class="col-sm-4 text-right") Address
                            .col-sm-6
                                input(
                                type="text"
                                name="address"
                                class="form-control"
                                id="address"
                                placeholder="Address"
                                required
                                )
                        .form-group.row
                            lable(for="password" class="col-sm-4 text-right") Password
                            .col-sm-6
                                input(
                                type="password"
                                name="password"
                                class="form-control"
                                id="password"
                                placeholder="Password"
                                required
                                )
                        .form-group.row
                            lable(for="password_confirmation" class="col-sm-4 text-right") Confirm Password
                            .col-sm-6
                                input(
                                type="password"
                                name="password_confirmation"
                                class="form-control"
                                id="password_confirmation"
                                placeholder="Confirm Password"
                                required
                                )
                        .form-group.row
                            lable.col-sm-4.text-right 验证码
                            #captcha.col-sm-6
                                p#wait.show 正在加载验证码......
                        .row
                            .col-sm-8.ml-sm-auto
                                button(type="submit" class="btn btn-dark" id="registerBtn")
                                    i(class="fa fa-sign-in" aria-hidden="true")
                                    |  Sign Up
append header
    script(src= CommonLibs + '/js/gt.js')
    script.
        function register(captchaObj) {
            var result = captchaObj.getValidate();
            if (!result) {
                return alert('请完成验证');
            }
            var name = $('input[name=name]').val();
            var pwd = $('input[name=password]').val();
            var cpwd = $('input[name=password_confirmation]').val();
            var sex = $('input[name=sex]:checked').val();
            var address = $('input[name=address]').val();
            var udate = new Date();
            if (name == '' || pwd == '' || cpwd == '' || sex == '' || address == '') {
                return false;
            }
            udate = udate.Format('yyyy-MM-dd hh:mm:ss');
            if ($.md5(pwd) != $.md5(cpwd)) {
                alert('The confirmation password is not identical.');
                return false;
            }
            var param = {
                uname: name,
                upwd: $.md5(pwd),
                usex: sex,
                uaddress: address,
                udate: udate
            };
            $.ajax({
                type: 'post',
                url: '/ghost/register',
                data: param,
                dataType: 'json',
                success: function (res) {
                    alert('Register Success');
                    window.location.href = '/login';
                },
                error: function (err) {
                    console.log(err);
                    captchaObj.reset();
                }
            });
            return false;
        }
        var handler = function (captchaObj) {
            captchaObj.appendTo('#captcha');
            captchaObj.onReady(function () {
                $("#wait").hide();
            });
            $('#registerBtn').click(function () {
                register(captchaObj);
            });
            // 更多接口说明请参见:http://docs.geetest.com/install/client/web-front/
            window.gt = captchaObj;
        };


        $.ajax({
            url: "gt/register-slide?t=" + (new Date()).getTime(), // 加随机数防止缓存
            type: "get",
            dataType: "json",
            success: function (data) {

                // 调用 initGeetest 进行初始化
                // 参数1:配置参数
                // 参数2:回调,回调的第一个参数验证码对象,之后可以使用它调用相应的接口
                initGeetest({
                    // 以下 4 个配置参数为必须,不能缺少
                    gt: data.gt,
                    challenge: data.challenge,
                    offline: !data.success, // 表示用户后台检测极验服务器是否宕机
                    new_captcha: data.new_captcha, // 用于宕机时表示是新验证码的宕机

                    product: "float", // 产品形式,包括:float,popup
                    width: "100%"
                    // 更多配置参数说明请参见:http://docs.geetest.com/install/client/web-front/
                }, handler);
            }
        });
        // 对Date的扩展,将 Date 转化为指定格式的String
        // 月(M)、日(d)、小时(h)、分(m)、秒(s)、季度(q) 可以用 1-2 个占位符,
        // 年(y)可以用 1-4 个占位符,毫秒(S)只能用 1 个占位符(是 1-3 位的数字)
        // 例子:
        // (new Date()).Format("yyyy-MM-dd hh:mm:ss.S") ==> 2006-07-02 08:09:04.423
        // (new Date()).Format("yyyy-M-d h:m:s.S")      ==> 2006-7-2 8:9:4.18
        Date.prototype.Format = function (fmt) { //author: meizz
            var o = {
                "M+": this.getMonth() + 1, //月份
                "d+": this.getDate(), //日
                "h+": this.getHours(), //小时
                "m+": this.getMinutes(), //分
                "s+": this.getSeconds(), //秒
                "q+": Math.floor((this.getMonth() + 3) / 3), //季度
                "S": this.getMilliseconds() //毫秒
            };
            if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
            for (var k in o)
                if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
            return fmt;
        }

index.pug
javascript 代码

extends layout
block opration-content
    a(class="nav-item nav-link" href="#") Holle,#{name}
    a(class="nav-item nav-link" href="/login") Login out
block content
    .jumbotron
        h1.display-3 Holle world!
        p.lead This is a simple hero unit, a simple jumbotron-style component for calling extra attention to featured content or information.
        hr.my-4
        p It uses utility classes for typography and spacing to space content out within the larger container.
        p.lead
            a(class="btn btn-primary btn-lg",href="#",role="button") Learn more

页面文件写好之后,修改app.js入口文件:
javascript 代码

var express = require('express');
var bodyParser = require('body-parser'); //用于处理 JSON, Raw, Text 和 URL 编码的数据
var app = express();
var router = require('./router/router');
var session = require('express-session');

//设置session配置
app.use(session({
    resave: false,  //重新保存
    saveUninitialized: true, //
    secret: 'ghost castle', //通过设置的 secret 字符串,来计算 hash 值并放在 cookie 中,使产生的 signedCookie 防篡改。
    cookie:{ maxAge: 1000*60*60} //失效时间
}));

app.use(bodyParser.json()); //解析json数据
app.use(bodyParser.urlencoded({ extended: true })); //解析form表单提交上来的数据

app.set('view engine', 'pug');            // 配置模板引擎
app.use(express.static('public'));
app.use('/', router);

var server = app.listen(3001, function() {

	var host = server.address().address;
	var port = server.address().port;

	console.log("http://%s:%s", host, port);

});

最后修改路由配置文件router.js
javascript 代码

const express = require('express');
const router = express.Router();
const Geetest = require('gt3-sdk'); //sdk
//极验配置
const captcha = new Geetest({
    geetest_id: '极验id',
    geetest_key: '极验key'
});

const user = require('../controllers/user');
const login = require('../controllers/login');
const Render  = (path, title) => ((req, res) => res.render(path, {title}))

//注册登录
router.post('/ghost/login', login.login);
router.post('/ghost/register', login.register);
//验证码
router.get('/gt/register-slide', function(req, res) {
    captcha.register(null, function (err, data) {
        if (err) {
            console.log(err);
            return;
        }
        if (!data.success) {
            // 进入 fallback,如果一直进入此模式,请检查服务器到极验服务器是否可访问
            // 可以通过修改 hosts 把极验服务器 api.geetest.com 指到不可访问的地址
            // 为以防万一,你可以选择以下两种方式之一:
            // 1. 继续使用极验提供的failback备用方案
            req.session.fallback = true;
            res.send(data);
            // 2. 使用自己提供的备用方案
            // todo
        } else {
            // 正常模式
            req.session.fallback = false;
            res.send(data);
        }
    });
});
router.post('/gt/validate-slide', function(req, res) {

    captcha.validate(req.session.fallback, {
        geetest_challenge: req.body.geetest_challenge,
        geetest_validate: req.body.geetest_validate,
        geetest_seccode: req.body.geetest_seccode
    }, function (err, success) {
        if (err) {
            // 网络错误
            res.send(err);
        } else if (!success) {
            // 二次验证失败
            res.send({"result" : false,"errorMsg": "登录失败,请完成验证"});
        } else {
            login.login(req, res);
            //res.send({"status" : "success"});
        }
    });
});

router.post('/get_user_info', user.getUserInfo);
router.post('/add_user_info', user.addUserInfo);
router.post('/update_user_info', user.updateUserInfo);
router.post('/delete_user_info', user.deleteUserInfo);
router.post('/export_user_info', user.exportUser); //导出excel


// 总路由
router.use(function(req, res, next) {
    global.CommonLibs = '';
    const url = req.originalUrl;
    if (url != "/login" && url != "/register" && !req.session.user) {
        return res.redirect("/login");
    }
    //next的作用是将请求转发,这个必须有,如果没有,请求到这就挂起了。
    next();
});

//  /list_user 页面 post 请求
router.get('/list_user', function(req, res) {
    res.sendfile('views/userList.html');
});
router.get('/login', Render('login', 'Login'));
router.get('/register', Render('signUp', 'Register'));
router.get('/', function(req, res){
    const user = req.session.user[0];
    res.render('index', {title: 'Home', name: user.uname});
});


module.exports = router;

运行效果如下(添加了极验的验证码校验):

登录页面

注册页面

登录并验证码校验

主页

github地址:github.com/ShanaFang00…