CentOS7 安裝 Node.js 建置 API加密認證(無DB服務)
server端: express + bcryptjs + body-parser
client端: jquery + AJAX(xhr) + cookie.js
7.網頁架構
登入頁面檔: public/index.html
註冊頁面檔: public/registration.html (一般不建議直接寫入資料庫檔案,存入另一個檔案+另外路徑試登比較好)
取用JSON資料頁面檔: public/sheet.html
首頁地址: https://192.168.0.1:3001 (這是範例,實際請改成server網址)
8.登入頁面(index.html)
把登入頁面當成首頁,驗證失敗都回來首頁
vim index.html
直接看程式碼
<html>
<head>
<title>LOGIN</title>
<style>
div.area {
background-color: #ace600; //黃綠色背景
text-align: center;
font-size: 40px;
}
</style>
<!-- 載入jquery跟cookie的plugin -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>
<script>
$(document).ready(function(){
$('#check_id').click(function(){
var User = $('#account').val(); //取得帳號的內容
var Pass = $('#secret').val(); //取得密碼的內容
if(User == ""){ //如果帳號為空白
//訊息欄顯示please fill user and pass
document.getElementById("showData").innerHTML = '<span style="color:red;">please fill user and pass</span>';
}else{
var info = { username: User, password: Pass }; //要送往api的json格式資料
var xhr = new XMLHttpRequest(); //使用XHR連線
xhr.open('post','https://192.168.10.1:3001/login',true); //使用post方法,true為非同步的方式
xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8'); //標頭設定為json request格式
xhr.send(JSON.stringify(info)); //將json內容轉成字串,才可以經由網址傳送
xhr.onload = function(){ //讀取時立刻執行
if(xhr.status == 200){ //狀態200是成功連線的狀態
var str = xhr.responseText; //回應值
if(str == "NO"){ //根據之前server的定義,是密碼錯誤
alert('account or password incorrect'); //彈出警告視窗,回應帳密錯誤
location.reload(); //頁面重置,重新讀取一次
}else if(str == "404"){ //根據之前server的定義,是使用者不存在
alert('account or password incorrect'); //不想讓人看出來沒帳號,故意也回帳密錯誤
location.reload();
}else{ //正確回應,根據之前server的定義,是json格式的session值
var conn_data = JSON.parse(str); //將回應存成json格式
$.cookie('name', User, { expires: 1, path: '/' }); //將帳號存成cookie值(name),1天後過期
$.cookie('session', conn_data.session, { expires: 1, path: '/' }); //將session值存成cookie值(session),1天後過期
//server端已設定4小時刪除session值,所以這邊expires不要為空值就好(不然重啟瀏覽器才會消失)
location.href = "https://192.168.0.1:3001/sheet.html"; //轉導到資料頁面
}
} else{
console.log('load data error!!'); //狀態200以外網頁回的錯誤訊息
}
}
}
});
});
</script>
</head>
<body>
<div class="area">
<span>user:</span><input type="text" id="account"><br>
<span>pass:</span><input type="password" id="secret"><br>
<button id="check_id">login</button>
<p id="showData"></p>
</div>
</body>
</html>
9.JSON資料頁面(sheet.html)
資料頁面不希望沒經過驗證的使用者瀏覽,所以必須做一點處理
直接看程式碼
<html>
<head>
<title>sheet data</title>
<style>
body{
background-color: #ace600;
}
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>
<script>
//檢查session值是否存在
$(document).ready(function(){
var Name = $.cookie('name'); //讀取cookie(name)內容
var Session = $.cookie('session'); //讀取cookie(session)內容
if(Name == undefined || Name == "" || Session == undefined || Session == ""){ //cookie為空值或沒定義
location.href = "https://192.168.0.1:3001/index.html"; //轉導到登入頁
}else{ //cookie有值
登入頁面檔: public/index.html
註冊頁面檔: public/registration.html (一般不建議直接寫入資料庫檔案,存入另一個檔案+另外路徑試登比較好)
取用JSON資料頁面檔: public/sheet.html
首頁地址: https://192.168.0.1:3001 (這是範例,實際請改成server網址)
8.登入頁面(index.html)
把登入頁面當成首頁,驗證失敗都回來首頁
vim index.html
直接看程式碼
<html>
<head>
<title>LOGIN</title>
<style>
div.area {
background-color: #ace600; //黃綠色背景
text-align: center;
font-size: 40px;
}
</style>
<!-- 載入jquery跟cookie的plugin -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>
<script>
$(document).ready(function(){
$('#check_id').click(function(){
var User = $('#account').val(); //取得帳號的內容
var Pass = $('#secret').val(); //取得密碼的內容
if(User == ""){ //如果帳號為空白
//訊息欄顯示please fill user and pass
document.getElementById("showData").innerHTML = '<span style="color:red;">please fill user and pass</span>';
}else{
var info = { username: User, password: Pass }; //要送往api的json格式資料
var xhr = new XMLHttpRequest(); //使用XHR連線
xhr.open('post','https://192.168.10.1:3001/login',true); //使用post方法,true為非同步的方式
xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8'); //標頭設定為json request格式
xhr.send(JSON.stringify(info)); //將json內容轉成字串,才可以經由網址傳送
xhr.onload = function(){ //讀取時立刻執行
if(xhr.status == 200){ //狀態200是成功連線的狀態
var str = xhr.responseText; //回應值
if(str == "NO"){ //根據之前server的定義,是密碼錯誤
alert('account or password incorrect'); //彈出警告視窗,回應帳密錯誤
location.reload(); //頁面重置,重新讀取一次
}else if(str == "404"){ //根據之前server的定義,是使用者不存在
alert('account or password incorrect'); //不想讓人看出來沒帳號,故意也回帳密錯誤
location.reload();
}else{ //正確回應,根據之前server的定義,是json格式的session值
var conn_data = JSON.parse(str); //將回應存成json格式
$.cookie('name', User, { expires: 1, path: '/' }); //將帳號存成cookie值(name),1天後過期
$.cookie('session', conn_data.session, { expires: 1, path: '/' }); //將session值存成cookie值(session),1天後過期
//server端已設定4小時刪除session值,所以這邊expires不要為空值就好(不然重啟瀏覽器才會消失)
location.href = "https://192.168.0.1:3001/sheet.html"; //轉導到資料頁面
}
} else{
console.log('load data error!!'); //狀態200以外網頁回的錯誤訊息
}
}
}
});
});
</script>
</head>
<body>
<div class="area">
<span>user:</span><input type="text" id="account"><br>
<span>pass:</span><input type="password" id="secret"><br>
<button id="check_id">login</button>
<p id="showData"></p>
</div>
</body>
</html>
9.JSON資料頁面(sheet.html)
資料頁面不希望沒經過驗證的使用者瀏覽,所以必須做一點處理
直接看程式碼
<html>
<head>
<title>sheet data</title>
<style>
body{
background-color: #ace600;
}
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>
<script>
//檢查session值是否存在
$(document).ready(function(){
var Name = $.cookie('name'); //讀取cookie(name)內容
var Session = $.cookie('session'); //讀取cookie(session)內容
if(Name == undefined || Name == "" || Session == undefined || Session == ""){ //cookie為空值或沒定義
location.href = "https://192.168.0.1:3001/index.html"; //轉導到登入頁
}else{ //cookie有值
//如果只想驗證session,只需藍色區塊(keep的api)
var xhr_login = new XMLHttpRequest();
xhr_login.open('get','https://192.168.0.1:3001/keep?username='+Name+'&session='+Session,true);
xhr_login.send();
xhr_login.onload = function(){
if(xhr_login.status == 200){ //連線成功
var str = xhr_login.responseText;
if(str == "OK"){ //驗證成功後運行的內容
var xhr_login = new XMLHttpRequest();
xhr_login.open('get','https://192.168.0.1:3001/keep?username='+Name+'&session='+Session,true);
xhr_login.send();
xhr_login.onload = function(){
if(xhr_login.status == 200){ //連線成功
var str = xhr_login.responseText;
if(str == "OK"){ //驗證成功後運行的內容
//如果要從api取得資料,只需要紫色的區塊(search的api)
var xhr = new XMLHttpRequest();
xhr.open('get','https://192.168.0.1:3001/search?username='+Name+'&session='+Session,true);
xhr.send();
xhr.onload = function(){
if(xhr.status == 200){ //連線成功
var str = JSON.parse(xhr.responseText);
if(str != "NO"){ //驗證成功
document.getElementById("showData").innerHTML = str;
//json資料可以呼叫變數取得對應值,這裡不做示範
}else{ //驗證失敗
location.href = "https://192.168.0.1:3001/index.html"; //轉導到登入頁
}
}else{ //連線失敗
console.log('資料讀取錯誤!!');
}
}
var xhr = new XMLHttpRequest();
xhr.open('get','https://192.168.0.1:3001/search?username='+Name+'&session='+Session,true);
xhr.send();
xhr.onload = function(){
if(xhr.status == 200){ //連線成功
var str = JSON.parse(xhr.responseText);
if(str != "NO"){ //驗證成功
document.getElementById("showData").innerHTML = str;
//json資料可以呼叫變數取得對應值,這裡不做示範
}else{ //驗證失敗
location.href = "https://192.168.0.1:3001/index.html"; //轉導到登入頁
}
}else{ //連線失敗
console.log('資料讀取錯誤!!');
}
}
}else{ //驗證失敗
location.href = "https://192.168.0.1:3001/index.html"; //轉導到登入頁
}
}else{ //連線失敗
console.log('load data error!!');
}
location.href = "https://192.168.0.1:3001/index.html"; //轉導到登入頁
}
}else{ //連線失敗
console.log('load data error!!');
}
}
}
$('#BTN').click(function(){ //登出按鈕功能
$.removeCookie('name', { path: '/' }); //刪除cookie(name)
$.removeCookie('session', { path: '/' }); //刪除cookie(session)
location.href = "https://192.168.0.1:3001/index.html"; //轉導到登入頁
});
$('#pause').click(function(){ //倒數暫停(pause)按鈕功能
pause = true; //根據下方功能定義,true為暫停
});
$('#resume').click(function(){ //倒數繼續(resume)按鈕功能
pause = false; //根據下方功能定義,faulse為繼續
});
});
//新增倒數功能
var pause = false; //判斷是否暫停的變數
countTimers(); //執行countTimer功能
function countTimers() { //定義countTimer功能
var count = 60; //倒數秒數
var counter = setInterval(timer, 1000); //新增迴圈物件,間隔1000毫秒執行timer功能
function timer() { //定義timer功能
if (!pause) { //如果沒有暫停,才執行程式
count = count - 1; //時間-1
if (count < 1) { //倒數時間歸零
clearInterval(counter); //刪除迴圈物件
document.getElementById("timer").innerHTML = 'next'; //秒數顯示next
location.reload(); //重新載入頁面
}else{ //倒數時間還沒歸零
document.getElementById("timer").innerHTML = count; //顯示剩餘秒數
}
}
}
}
</script>
</head>
<body>
<p>Refresh in <span id="demo" style="color:red;">60</span> seconds.<button id="pause">Pause</button><button id="resume">Resume</button> <input type="button" id="BTN" value="Logout" style="float: right;"></p>
<p id="showData"></p>
</body>
</html>
如此一來,你所有的頁面都可以加上這段程式碼,達到驗證的目的,正常的範例到這裡結束
10.註冊頁面(registration.html)
因為這是建議額外處理的項目,所以並沒有在前面的主設定檔內
# server端
vim app.js
增加一段api驗證,與登入一樣使用POST
以下是直接加入資料庫檔data.js裡的範例
app.post('/register', async (req, res) => {
try{
let foundUser = users.find((data) => req.body.email === data.email);
if (!foundUser) {
//將密碼加密
let hashPassword = await bcrypt.hash(req.body.password, 10);
//新增使用者格式
let newUser = {
id: Date.now(),
username: req.body.username,
email: req.body.email,
password: hashPassword,
};
//console.log(newUser); //直接顯示新使用者資料的方式(不寫入)
//加入記憶體陣列(馬上能登入)
users.push(newUser);
//console.log('User list', users); //除錯用,會顯示所有使用者json資料
//存入檔案,重啟不會消失
let Head = 'const userDB = ';
let str = JSON.stringify(users);
let Foot = ';\nmodule.exports = { userDB };';
const Newdata = Head + str + Foot;
const filename ='data.js';
fs.writeFile(filename, Newdata, function (error) { //將記憶體陣列的json寫回檔案
//console.log('user login'); //除錯用
});
//註冊成功傳回訊息
res.send("<div align ='center'><h2>Registration successful</h2></div><br><br><div align='center'><a href='./index.html'>login</a></div><br><br><div align='center'><a href='./registration.html'>Register another user</a></div>");
} else { //信箱重複註冊失敗傳回訊息
res.send("<div align ='center'><h2>Email already used</h2></div><br><br><div align='center'><a href='./registration.html'>Register again</a></div>");
}
} catch{ //意外錯誤的回傳信息
res.send("Internal server error");
}
});
# client端網頁
vim registration.html
新增以下內容(不是版主寫的,但覺得能用就沒改內容)
<html>
<head>
<meta charset = "UTF-8">
<title> My Form </title>
<style>
#mylink{
font-size: 25px;
}
</style>
</head>
<body align='center'>
<header>
<h1>Register</h1>
</header>
<form action="/register" method="POST">
<fieldset>
<label>Username</label>
<input type ="text" id = 'username' name="username" placeholder="maverick" required>
<br><br>
<label>Email ID</label>
<input type ="email" id = 'email' name="email" placeholder="[email protected]" required>
<br><br>
<label>Password</label>
<input type="password" id = "password" name="password" required>
<br><br>
<button type ="reset">Reset</button>
<button type ="submit">Submit</button>
</fieldset>
</form>
<br><br>
<a id="mylink" href="./login.html">login</a>
</body>
</html>
想要知道加密後的密碼,就可以用這個頁面註冊,用不寫入的方式顯示,再手動加入data.js即可
範例到此完全結束,謝謝您努力看完~~~
}
$('#BTN').click(function(){ //登出按鈕功能
$.removeCookie('name', { path: '/' }); //刪除cookie(name)
$.removeCookie('session', { path: '/' }); //刪除cookie(session)
location.href = "https://192.168.0.1:3001/index.html"; //轉導到登入頁
});
$('#pause').click(function(){ //倒數暫停(pause)按鈕功能
pause = true; //根據下方功能定義,true為暫停
});
$('#resume').click(function(){ //倒數繼續(resume)按鈕功能
pause = false; //根據下方功能定義,faulse為繼續
});
});
//新增倒數功能
var pause = false; //判斷是否暫停的變數
countTimers(); //執行countTimer功能
function countTimers() { //定義countTimer功能
var count = 60; //倒數秒數
var counter = setInterval(timer, 1000); //新增迴圈物件,間隔1000毫秒執行timer功能
function timer() { //定義timer功能
if (!pause) { //如果沒有暫停,才執行程式
count = count - 1; //時間-1
if (count < 1) { //倒數時間歸零
clearInterval(counter); //刪除迴圈物件
document.getElementById("timer").innerHTML = 'next'; //秒數顯示next
location.reload(); //重新載入頁面
}else{ //倒數時間還沒歸零
document.getElementById("timer").innerHTML = count; //顯示剩餘秒數
}
}
}
}
</script>
</head>
<body>
<p>Refresh in <span id="demo" style="color:red;">60</span> seconds.<button id="pause">Pause</button><button id="resume">Resume</button> <input type="button" id="BTN" value="Logout" style="float: right;"></p>
<p id="showData"></p>
</body>
</html>
如此一來,你所有的頁面都可以加上這段程式碼,達到驗證的目的,正常的範例到這裡結束
10.註冊頁面(registration.html)
因為這是建議額外處理的項目,所以並沒有在前面的主設定檔內
# server端
vim app.js
增加一段api驗證,與登入一樣使用POST
以下是直接加入資料庫檔data.js裡的範例
app.post('/register', async (req, res) => {
try{
let foundUser = users.find((data) => req.body.email === data.email);
if (!foundUser) {
//將密碼加密
let hashPassword = await bcrypt.hash(req.body.password, 10);
//新增使用者格式
let newUser = {
id: Date.now(),
username: req.body.username,
email: req.body.email,
password: hashPassword,
};
//console.log(newUser); //直接顯示新使用者資料的方式(不寫入)
//加入記憶體陣列(馬上能登入)
users.push(newUser);
//console.log('User list', users); //除錯用,會顯示所有使用者json資料
//存入檔案,重啟不會消失
let Head = 'const userDB = ';
let str = JSON.stringify(users);
let Foot = ';\nmodule.exports = { userDB };';
const Newdata = Head + str + Foot;
const filename ='data.js';
fs.writeFile(filename, Newdata, function (error) { //將記憶體陣列的json寫回檔案
//console.log('user login'); //除錯用
});
//註冊成功傳回訊息
res.send("<div align ='center'><h2>Registration successful</h2></div><br><br><div align='center'><a href='./index.html'>login</a></div><br><br><div align='center'><a href='./registration.html'>Register another user</a></div>");
} else { //信箱重複註冊失敗傳回訊息
res.send("<div align ='center'><h2>Email already used</h2></div><br><br><div align='center'><a href='./registration.html'>Register again</a></div>");
}
} catch{ //意外錯誤的回傳信息
res.send("Internal server error");
}
});
# client端網頁
vim registration.html
新增以下內容(不是版主寫的,但覺得能用就沒改內容)
<html>
<head>
<meta charset = "UTF-8">
<title> My Form </title>
<style>
#mylink{
font-size: 25px;
}
</style>
</head>
<body align='center'>
<header>
<h1>Register</h1>
</header>
<form action="/register" method="POST">
<fieldset>
<label>Username</label>
<input type ="text" id = 'username' name="username" placeholder="maverick" required>
<br><br>
<label>Email ID</label>
<input type ="email" id = 'email' name="email" placeholder="[email protected]" required>
<br><br>
<label>Password</label>
<input type="password" id = "password" name="password" required>
<br><br>
<button type ="reset">Reset</button>
<button type ="submit">Submit</button>
</fieldset>
</form>
<br><br>
<a id="mylink" href="./login.html">login</a>
</body>
</html>
想要知道加密後的密碼,就可以用這個頁面註冊,用不寫入的方式顯示,再手動加入data.js即可
範例到此完全結束,謝謝您努力看完~~~