Node.JS學習筆記(八)_express登入介面導入跳轉測試_EJS模板引擎_路由跳轉

 



cd /d D:\Projects\ReactAPI
mkdir node_login
cd node_login
npm init --yes
npm install express
npm install ejs
cd. > index.js




準備一個login頁面雛形
放置views目錄(新增一個存放檢視的folder)



  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Login</title>
  <style type="text/css">
    body {
  background: #456;
  font-family: 'Open Sans', sans-serif;
}

.login {
  width: 400px;
  margin: 16px auto;
  font-size: 16px;
}

/* Reset top and bottom margins from certain elements */
.login-header,
.login p {
  margin-top: 0;
  margin-bottom: 0;
}

/* The triangle form is achieved by a CSS hack */
.login-triangle {
  width: 0;
  margin-right: auto;
  margin-left: auto;
  border: 12px solid transparent;
  border-bottom-color: #28d;
}

.login-header {
  background: #28d;
  padding: 20px;
  font-size: 1.4em;
  font-weight: normal;
  text-align: center;
  text-transform: uppercase;
  color: #fff;
}

.login-container {
  background: #ebebeb;
  padding: 12px;
}

/* Every row inside .login-container is defined with p tags */
.login p {
  padding: 12px;
}

.login input {
  box-sizing: border-box;
  display: block;
  width: 100%;
  border-width: 1px;
  border-style: solid;
  padding: 16px;
  outline: 0;
  font-family: inherit;
  font-size: 0.95em;
}

.login input[type="email"],
.login input[type="password"] {
  background: #fff;
  border-color: #bbb;
  color: #555;
}

/* Text fields' focus effect */
.login input[type="email"]:focus,
.login input[type="password"]:focus {
  border-color: #888;
}

.login input[type="submit"] {
  background: #28d;
  border-color: transparent;
  color: #fff;
  cursor: pointer;
}

.login input[type="submit"]:hover {
  background: #17c;
}

/* Buttons' focus effect */
.login input[type="submit"]:focus {
  border-color: #05a;
}
  </style>
</head>
<body>
<div class="login">
  <div class="login-triangle"></div>
  
  <h2 class="login-header">Log in</h2>

  <form class="login-container">
    <p><input type="email" placeholder="Email"></p>
    <p><input type="password" placeholder="Password"></p>
    <p><input type="submit" value="Log in"></p>
  </form>
</div>
</body>
</html>





在此刻意改放置於front目錄


改寫index.js (程式進入點)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
let express = require("express");

let app = express();

let ejs = require("ejs");

//設置template檢視放置的位置
//(固定views,模板存放之相對目錄)
app.set("views","./views");

//設置要使用的template engine
//(模板引擎的名稱(模板檔案之附檔名),使用模板引擎方法)
app.engine("html",ejs.__express);

app.set("view engine","html");


app.get('/',function(req,res,next){
	//req : request物件(from client)
	//res : response物件(from server)
	//next : 運行下一個方法
	//res.send("我是一個Node網頁");
	res.render("front/login");
	
});


app.listen(3000 , function() {
	console.log("node server 已啟動,port:3000");
});

再次運行就可發現預設會導向我們指定的html 檢視


預設若要模擬登入成功
我們可以在本機寫死member物件陣列的假資料

記得進行npm install body-parser 
用於post 解析表單body資料

index.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
let express = require("express");

let app = express();

const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({extended:false}));

let ejs = require("ejs");

//設置template檢視放置的位置
//(固定views,模板存放之相對目錄)
app.set("views","./views");

//設置要使用的template engine
//(模板引擎的名稱(模板檔案之附檔名),使用模板引擎方法)
app.engine("html",ejs.__express);

app.set("view engine","html");


app.get('/',function(req,res,next){
	//req : request物件(from client)
	//res : response物件(from server)
	//next : 運行下一個方法
	//res.send("我是一個Node網頁");
	res.render("front/login");
	
});

const Members = [
    { id: 1, account: "aaa@gmail.com", passwd: "abc1" },
    { id: 2, account: "bbb@gmail.com", passwd: "abc2" },
    { id: 3, account: "ccc@gmail.com", passwd: "abc3" },
    { id: 4, account: "ddd@gmail.com", passwd: "abc4" }
];



app.post('/login',function(req,res,next){
	console.log("登入");
    console.log(req.body);
	let {user_account,user_passwd} = req.body;
	
	let acc = user_account?.trim() || '';
	let pwd = user_passwd?.trim() || '';
	
	const member = Members.filter(function(mem){
		if(mem.account == acc && mem.passwd == pwd)
		{
			return true;
		}
		return false;
	});
	console.log(member);
	
	if(member.length>0){
		res.send("<script>alert('登入成功');window.location.href='/';</script>");
	}else{
		res.send("<script>alert('無此會員帳號(信箱)');window.location.href='/';</script>");
	}
	
});



app.listen(3000 , function() {
	console.log("node server 已啟動,port:3000");
});


如果找到match的會員資料則




如果找不到則






在進行路由跳轉上可以在做location的指定
目前都是跳回原先首頁路由指定的login portal

在此可擴充三個路由
暫時先寫死回傳字串

1
2
3
4
5
6
7
8
9
app.get('/north',function(req,res,next){
	res.send("北部地區");
});
app.get('/south',function(req,res,next){
	res.send("南部地區");
});
app.get('/central',function(req,res,next){
	res.send("中部地區");
});


模擬會員寫死資料庫的物件陣列多擴充一個地區欄位

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
let express = require("express");

let app = express();

const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({extended:false}));

let ejs = require("ejs");

//設置template檢視放置的位置
//(固定views,模板存放之相對目錄)
app.set("views","./views");

//設置要使用的template engine
//(模板引擎的名稱(模板檔案之附檔名),使用模板引擎方法)
app.engine("html",ejs.__express);

app.set("view engine","html");


app.get('/',function(req,res,next){
	//req : request物件(from client)
	//res : response物件(from server)
	//next : 運行下一個方法
	//res.send("我是一個Node網頁");
	res.render("front/login");
	
});

const Members = [
    { id: 1, account: "aaa@gmail.com", passwd: "abc1",position:"北部" },
    { id: 2, account: "bbb@gmail.com", passwd: "abc2",position:"中部" },
    { id: 3, account: "ccc@gmail.com", passwd: "abc3",position:"南部" },
    { id: 4, account: "ddd@gmail.com", passwd: "abc4",position:"北部" }
];

app.get('/north',function(req,res,next){
	res.send("北部地區");
});
app.get('/south',function(req,res,next){
	res.send("南部地區");
});
app.get('/central',function(req,res,next){
	res.send("中部地區");
});


app.post('/login',function(req,res,next){
	console.log("登入");
    console.log(req.body);
	let {user_account,user_passwd} = req.body;
	
	let acc = user_account?.trim() || '';
	let pwd = user_passwd?.trim() || '';
	
	const member = Members.filter(function(mem){
		if(mem.account == acc && mem.passwd == pwd)
		{
			return true;
		}
		return false;
	});
	console.log(member);
	
	if(member.length>0){
		let pos = member[0].position.trim();
		let pos_url = "";
		switch(pos){
			case '北部' :
				pos_url = "north";
				break;
			case '中部' :
				pos_url = "central";
				break;
			case '南部' :
				pos_url = "south";
				break;
		}
		//javascript string interpolation
		res.send(`<script>alert('登入成功');window.location.href='/${pos_url}';</script>`);
	}else{
		res.send("<script>alert('無此會員帳號(信箱)');window.location.href='/';</script>");
	}
	
});



app.listen(3000 , function() {
	console.log("node server 已啟動,port:3000");
});




那如何落實權限控管?
避免使用者直接跳過login 直接key url就可存取另外3頁呢?

這裡可以去安裝
express-session
讓資料keep在server做狀態保存藉此進行登入後身分的狀態存留

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
let express = require("express");

let app = express();

const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({extended:false}));

//處理session 配置
const session = require('express-session');
app.use(session({
	secret: 'keyboard cat',
	resave: false,
	saveUninitialized: true
}))

let ejs = require("ejs");

//設置template檢視放置的位置
//(固定views,模板存放之相對目錄)
app.set("views","./views");

//設置要使用的template engine
//(模板引擎的名稱(模板檔案之附檔名),使用模板引擎方法)
app.engine("html",ejs.__express);

app.set("view engine","html");

app.use(function (req, res, next) {
	console.log(req.url);//url 路徑判斷是否能直接進行訪問
	if(req.url != "/" && req.url != "/login")
	{
		if (req.session.acc && req.session.pwd) {
			console.log("已登入");
            next();
        } else {
            res.send("<script>alert('請先登入');top.location.href='/'</script>");
        }
	} else {
        next();
    }
	
});

app.get('/',function(req,res,next){
	//req : request物件(from client)
	//res : response物件(from server)
	//next : 運行下一個方法
	//res.send("我是一個Node網頁");
	res.render("front/login");
	
});

const Members = [
    { id: 1, account: "aaa@gmail.com", passwd: "abc1",position:"北部" },
    { id: 2, account: "bbb@gmail.com", passwd: "abc2",position:"中部" },
    { id: 3, account: "ccc@gmail.com", passwd: "abc3",position:"南部" },
    { id: 4, account: "ddd@gmail.com", passwd: "abc4",position:"北部" }
];

app.get('/north',function(req,res,next){
	res.send("北部地區");
});
app.get('/south',function(req,res,next){
	res.send("南部地區");
});
app.get('/central',function(req,res,next){
	res.send("中部地區");
});


app.post('/login',function(req,res,next){
	console.log("登入");
    console.log(req.body);
	let {user_account,user_passwd} = req.body;
	
	let acc = user_account?.trim() || '';
	let pwd = user_passwd?.trim() || '';
	
	const member = Members.filter(function(mem){
		if(mem.account == acc && mem.passwd == pwd)
		{
			return true;
		}
		return false;
	});
	console.log(member);
	
	if(member.length>0){
		let pos = member[0].position.trim();
		let pos_url = "";
		switch(pos){
			case '北部' :
				pos_url = "north";
				break;
			case '中部' :
				pos_url = "central";
				break;
			case '南部' :
				pos_url = "south";
				break;
		}
		req.session.acc = member[0].account;
		req.session.pwd = member[0].passwd;
		//javascript string interpolation
		res.send(`<script>alert('登入成功');window.location.href='/${pos_url}';</script>`);
	}else{
		res.send("<script>alert('無此會員帳號(信箱)');window.location.href='/';</script>");
	}
	
});



app.listen(3000 , function() {
	console.log("node server 已啟動,port:3000");
});

那也可更進一步去設計若今天這個會員登入者就只能存取其相應所屬區域的頁面路由






留言

這個網誌中的熱門文章

何謂淨重(Net Weight)、皮重(Tare Weight)與毛重(Gross Weight)

Architecture(架構) 和 Framework(框架) 有何不同?_軟體設計前的事前規劃的藍圖概念

經得起原始碼資安弱點掃描的程式設計習慣培養(五)_Missing HSTS Header