owned this note
owned this note
Published
Linked with GitHub
https://www.youtube.com/watch?v=SnoAwLP1a-0&list=PL4cUxeGkcC9iqqESP8335DA5cRFp8loyp
gitHub
https://github.com/iamshaunjp/node-express-jwt-auth/tree/lesson-1
[TOC]
# Introduction & SetUp
Json web token -> Authentication systems management (驗證系統管理)
```
USER@DESKTOP-QGJ2K9H MINGW64 ~/Desktop/NQUCS/Web/jwtAuth (master)
$ git clone --branch lesson-1 https://github.com/iamshaunjp/node-express-jwt-auth.git
```
## ejs
(embedded javascript) -> 模板 data embeding 到 前端
據動態數據生成frontend內容
## Express
可以把EXPRESS -> 想成Frame work 主架構
基於路由的方式來 處理HTTP請求
## package.json
```json
{
"name": "node-express-jwt-auth",
"version": "1.0.0",
"description": "",
"main": "app.js",
"dependencies": {
"ejs": "^3.1.3",
"express": "^4.17.1",
"mongoose": "^5.9.23"
},
"devDependencies": {},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/iamshaunjp/node-express-jwt-auth.git"
},
"keywords": [],
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/iamshaunjp/node-express-jwt-auth/issues"
},
"homepage": "https://github.com/iamshaunjp/node-express-jwt-auth#readme"
}
```
Install packages
```
npm install
```
可以即時跟新對web 修改
```
npm install nodemon -g
```
Run web application
```
nodemon app
```
## MongoDB 設定
### 在Windows上安裝 MongoDB
```
`C:\> wmic os get osarchitecture`
```
MongoDB Download
https://www.mongodb.com/try/download/community
確定computer archi
創建 MongoDB 帳戶
到 Security
Create 一個 user Account
加入自己的IP
取得 Node js appplication (DB 連結)

### 創建Database (on cloud) and user Table

Clicking on Browse Collection.
Add My own Data

設定 Package.json
```
PS C:\Users\USER\Desktop\NQUCS\Web\nodeJsConnetToDB> npm init
```
entry point -> main program (入口)
```
package name: (nodejsconnettodb) connect_to_db
version: (1.0.0)
description: meow
entry point: (index.js) server.js
test command:
git repository:
keywords:
author: MeowHacker
license: (ISC) MIT
```
安裝Mongo DB driver 跟 Express
```
npm install express
npm install mongoose --save
```
### server.js (Verify)
```
//basic set up,
//import lib
const express = require("express");
const mongoose = require("mongoose");
const server = express();
const DBurl = "mongodb+srv://<userName>:<password>@cluster0.3zudqmo.mongodb.net/nodeAuth"
async function connetToMongoDB () {
try{
await mongoose.connect(DBurl)
console.log("Connect to mogoDB !!")
} catch(error){
console.error(error)
}
}
connetToMongoDB();
server.listen(8000,()=>{
console.log("Server started on the port 8000")
});
```
## Run app.js
```javascript
const express = require('express');
const mongoose = require('mongoose');
const app = express();
// middleware
app.use(express.static('public'));
// view engine
app.set('view engine', 'ejs');
// database connection 要記得url 設定DB name
const DBurl = "mongodb+srv://<account>:<password>@cluster0.3zudqmo.mongodb.net/nodeAuth"
async function connetToMongoDB () {
try{
await mongoose.connect(DBurl, { useNewUrlParser: true, useUnifiedTopology: true, useCreateIndex:true })
console.log("Connect to mogoDB !!")
} catch(error){
console.error(error)
}
}
connetToMongoDB()
app.listen(8001,()=>{
console.log("app started on the port 8001")
});
// routes
app.get('/', (req, res) => res.render('home'));
app.get('/smoothies', (req, res) => res.render('smoothies'));
```
MiddleWare
中間件(Middleware)是在請求(Request)和回應(Response)處理之間執行的函式
靜態資源伺服器
可以根據請求的 URL 路徑將(Request)映射到相應的靜態檔案,並將其發送(Response)給客戶端
使我們Run COde 比較不會錯
```
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex:true
```
async -> 完成或return promise
Promis -> 表示Function 未來狀態
Promise 可以有三種狀態:
- 等待(pending)、
- 已實現(fulfilled)
- 已拒絕(rejected)
Promise 提供了 `then()` 方法,使我們能夠在 Promise 被解決後執行相應的處理邏輯
`then()` 來鏈接多個 Promise
e.g.
```javascript
const myPromise = new Promise((resolve, reject) => {
// 非同步操作
// 成功時調用 resolve(value)
// 失敗時調用 reject(error)
});
myPromise.then((value) => {
// 當 Promise 成功解決時執行的處理邏輯
}).catch((error) => {
// 當 Promise 拒絕時執行的錯誤處理邏輯
});
```
```javascript
connetToMongoDB.then((value)=>{ //function return resolve
server.listen(8000)
console.log("Server started on the port 8000")
}).ecath((error)=>{ // funcition return reject
console.error(error)
})
```
## localhost:8001
### FireWall (disable for the DB Connection )
Attension: 連到Cloud server 防火牆 要關

```
PS C:\Users\USER\Desktop\NQUCS\web\jwtAuth\node-express-jwt-auth-1> node .\app.js
app started on the port 8001
Connect to mogoDB !!
```
# Auth Routes &
MVC Model (model,view,controller)

Router (獨立一個 Folder)
```javascript
const {Router} = require('express')
const router = Router()
router.get('/signup', ()=>{})
router.post('/signup', ()=>{})
router.get('/login', ()=>{})
router.post('/login', ()=>{})
router.get('/logout', ()=>{})
module.exports = router
```
---
Controller
```javascript
module.exports.signupGet = ((request,response) => {
response.render('signup')
})
module.exports.signupPost = ((request,response) => {
response.send('new sighup!!')
})
module.exports.loginGet = ((request,response) => {
response.render('login')
})
module.exports.loginPost = ((request,response) => {
response.send('user Login ')
})
```
Render -> 會去Views 下找 ejs 來用
---
把Controller 跟 Router 合起來
```javascript
const {Router} = require('express')
const authController = require('../controllers/authController')
const router = Router()
router.get('/signup', authController.signupGet)
router.post('/signup', authController.signupPost)
router.get('/login', authController.loginGet)
router.post('/login', authController.loginPost)
router.get('/logout', ()=>{})
module.exports = router
```
再把創好的Router 放到 Express 來執行

# Testing Routing & Handling Post Request
Post man 有點像 burtSuite 的Repeter module

也能測試 Post request 請求

## Post reqeust (json handle)
node.js 要處理 Post request 中的 json 需要有middleware(javascrpt object) 幫忙 並在js 程序中使用 client 傳過來的json 資料
```
// middleware
app.use(express.static('public'));
//parse json data
app.use(express.json())
```
controller
```
module.exports.loginPost = ((request,response) => {
console.log(request.body)
//拆成不同變數
const {userName, password} = request.body //variable Name 要跟json key 一樣
console.log (userName,password)
response.send('user Login ')
})
```
Post Request

Result

# User Model
這裡的Model -> 有點像是 定義 table 表
提供給controller 來做動作(Action)
## Defind User table
```javascript=
const mongoose = require('mongoose')
//table form
const userSchema = new mongoose.Schema({
username:{
type:String,
required:true,
unique:true,
lowercase:true
},
password:{
type:String,
required:true,
minLength:6
}
})
const User = mongoose.model('user',userSchema)
module.exports = User
```
## Create New user
他是async function
User.create({username,password}) 會回傳promise
```javascript
module.exports.signupPost = async (request,response) => {
const {username,password} = request.body
try {
const user = await User.create({username,password}) // this function is async, it's will get a promise
response.status(201).json(user) // response to Browser
response.send('new sighup!!')
}
catch(error){
console.log(error)
response.status(400).send("error, user not created !! ")
}
}
```
User Create Controller
```javascript
module.exports.signupPost = async (request,response) => {
const {username,password} = request.body
try {
const user = await User.create({username,password}) // this function is async, it's will get a promise
response.status(201).json(user) // response to Browser
response.send('new sighup!!')
}
catch(error){
console.log(error)
response.status(400).send("error, user not created !! ")
}
}
```
Post Request

## Mongoose Validation
```
npm install validator
```
```javascript
//table form
const userSchema = new mongoose.Schema({
username:{
type:String,
required:[true,'Please enter an email'],
unique:true,
lowercase:true,
//validate:[isEmail,'please enter a valid email']
},
password:{
type:String,
required:[true,'Please enter a password'],
minlength:[6,'Minimum password length is 6 characters']
}
})
```
可以透過array 來 存Error Message


Error Code = undefined !!
---
Error Handler
要去提取 property 裡面的error message
```
console.log(errorObj)
```

objectValue(object) -> 把Object 塞進Array -> 來做遍歷
```
const handleErrors = (errorObj)=>{
//console.log(errorObj.message,errorObj.code)
let errors ={username:"",password:""}
if(errorObj.message.includes('user validation failed')){
console.log(Object.values(errorObj.errors))
}
}
```

---
在這個 object Array 用forEech 取出property
```
const handleErrors = (errorObj)=>{
//console.log(errorObj.message,errorObj.code)
let errors ={username:"",password:""}
if(errorObj.message.includes('user validation failed')){
Object.values(errorObj.errors).forEach(error => {
console.log(error.properties)
})
}
}
```
質佳抓 property object
```
const handleErrors = (errorObj)=>{
//console.log(errorObj.message,errorObj.code)
let errors ={username:"",password:""}
if(errorObj.message.includes('user validation failed')){
Object.values(errorObj.errors).forEach(({properties}) => {
console.log(properties)
})
}
}
```
Return ErrorMessage (json)(done)
```javascript
const handleErrors = (errorObj)=>{
//console.log(errorObj.message,errorObj.code)
let errorsMessages ={username:'',password:''}
if(errorObj.message.includes('user validation failed')){
Object.values(errorObj.errors).forEach(({properties}) => {
console.log(properties)
errorsMessages[properties.path] = properties.message
})
}
//console.log(errorsMessages)
return errorsMessages // return error with json form
}
```

(Controller) Return Json form to client
```javascript
atch(error){
const errorsMessages = handleErrors(error) //return javascript Object
console.log(errorsMessages)
response.status(400).json({errorsMessages})
}
```
---

Check duplication email
```javascript
//duplication error code
if (errorObj.code === 11000){
errorsMessages.email = "that email is already registred!!"
return errorsMessages
}
```
----
# Mongoose Hook
Hook -> 有點像middleware
能對 資料進行 pre-procses or post-process
## post-process
post function -> 會處於hungry 等待next() 被執行
```javascript
// Mongoose Hook
// fire a function after data save to database
userSchema.post('save', function(doc, next){
//function -> hungry function -> 會等待next()
console.log('new user create & save',doc);
//next()
})
```
```
[nodemon] starting `node .\app.js`
app started on the port 8001
Connect to mogoDB !!
new user create & save {
_id: 64b1b17e9986603164eb87b4,
username: 'meowhe1ck1err1rr',
password: 'testwr1e1wrw1123',
__v: 0
}
```
他在 Response 掛起了
Response
server --Hook(post-process)--> client

他是有傳到DB的
---
有next () 下
```
// fire a function after data save to database
userSchema.post('save', function(doc, next){
//function -> hungry function -> 會等待next()
console.log('new user create & save',doc);
next()
})
```

## pre-Process
在save to Cloud DB 之前 觸發Funciton
我們能在取得request 後去做處理
request
clinet --->Hook--->server
```javascript
// fire a function Before data save to database
userSchema.pre('save', function(next){
//this (local instance, controller User 那個變數)
console.log('new user about created & saved',this)
next()
})
```
```
app started on the port 8001
Connect to mogoDB !!
new user about created & saved {
_id: 64b1b5cdc020060274a4d95f,
username: 'meowhe1ck111e1rr1rr',
password: 'testwr1e1wrw1111323'
}
{
username: '',
password: '',
email: 'that email is already registred!!'
```
# Hashing the password
bcrypt -> 加密算法
packet JSON
```
npm install bcrypt
```



透過加salt 方式 避免 Ranbow attack
在登入時 會先將 輸入的password加salt 跟DB中Hash password 做比較喔
## Hash the password
增加以點security (salt)
```
userSchema.pre('save', async function(next){
const salt = await bcrypt.genSalt()
this.password = await bcrypt.hash(this.password, salt)
next()
})
```
this -> local instance (User)


# Authentication View
Form
```htmlmixed=
<form>
<h2>Sign up page</h2>
<label for="username">UserName</label>
<input type="text" name="username" required/>
<div class="username error"></div>
<label for="password">Password</label>
<input type="password" name="password" requiere/>
<div class="password error"></div>
<button>Sign up</button>
</form>
```
## Grabbing the value from the form
```htmlmixed=
<script>
const formElement = document.querySelector('form')
formElement.addEventListener('submit',(event)=>{ //監聽submit 事件
event.preventDefault(event) //subit Defaut event -> prevent refresh page (不然會送不了)
//get the vale from form
const username = formElement.username.value
const password = formElement.password.value
console.log(username,password)
})
</script>
```

# Cookies
cookie -> 可以放data 在User 的Browser
跟蹤在internet 上的活動e.g. google analysis

---

---
第2次使用website

cookie 裡面可以有一個(jwt) 來authentication User 身分
vulnerable -> CSRF
## Set the cookie
```javascript
app.get('/set-cookies', (request,response)=>{
response.setHeader('Set-Cookie', 'NewUser=ture')
response.send("you got the cookies !!")
})
```


## Parse cookie (使用cookie)
packages
```
npm install cookie-parser
```

middleware
每個傳送到 Web application 的cookie 都可以讀到
```
app.use(cookieParser())
```
```
resonse.cookie("IsEmployee",ture,{maxAge: 1000* 60 * 60 *24, secure:true, httponly:true}) //expire 1 天
```
cookie 可以接 object attribute
secure: 只會在HTTPS 下傳送
httpOnly: 無法使用js Read the cookie

如果沒有設定 expire -> close browser, cookie will be removed
```javascript
app.get('/set-cookies', (request,response)=>{
//response.setHeader('Set-Cookie', 'NewUser=ture') //basic way
response.cookie("NewUser",false)
response.cookie("IsEmployee",true,{maxAge: 1000* 60 * 60 *24, secure:true, httpOnly:true}) //expire 1 天
response.send("you got the cookies !!") //response body
})
```

## Read Cookies
```javascript
app.get('/read-cookies',(request,response)=>{
const cookies = request.cookies
console.log(cookies)
console.log(cookies.NewUser)
console.log(cookies.IsEmployee)
response.json(cookies) //read the cookie and send back to the browser
})
```
可以透過 cookies.Keyname -> 來取得cookie 特定的value
```
{ NewUser: 'false', IsEmployee: 'true' }
false
true
```

# Json web token
Client Send account 跟 password 到server 並檢查 跟Database 中的 password(hash) 如果一樣會創建 JWT 給client 存在Client Browser
JWT data (經過身分認證)
會有自身身分(用來識別身分)
他會被進行特殊 Encode or Encrypte
當client 訪問其他需要登入Page時
Server 就會 parser Client 送過來的Cookie 裡的Token

JWT token -> 如果能被Attacker 拿到會有CSRF 問題
## State Change Endpoint
更改端點-> 會對 Web application 進行跟新或更改的URL
狀態更改端點使用 HTTP 方法 e.g. GET、POST、PUT、DELETE 等
## CSRF
Attacke way 1
1. 受害者訪問惡意網站。
2. 惡意網站中的 JavaScript 代碼自動觸發請求到資料更改端點。
3. 該請求中包含攻擊者生成的 JWT,因為 JWT 已存儲在受害者的瀏覽器中(例如,Cookie 中)。
4. 資料更改端點收到請求,驗證 JWT,並認為該請求是合法的,因為 JWT 的簽名是有效的。
5. 資料更改端點執行請求中指定的操作,並將結果返回給攻擊者的網站。
Attacke way 2
透過XSS 來取的Browser Cookie 傳回Server
## JWT implement
[JWT debugger](https://jwt.io/)
由3個部分組成
### Header
使用什麼算法 encod
### payload
User 一些data
### signature
確保data 不備竄改


JWT signing


### JWT bypass (加密失效)
我們可以把signature 的alg 改成none -> 去刪signature
我們在串改 username 就不會被發現
# New User Signup
## Http request to Backend (fetch API)
front-end send the username and password to back-end
前端透過fetch 來做出 request 來與back-end 互動
```javascript=
<script>
const formElement = document.querySelector('form')
formElement.addEventListener('submit',async (event)=>{ //監聽submit 事件
event.preventDefault(event) //subit Defaut event -> refresh page
//get the vale from form
const username = formElement.username.value
const password = formElement.password.value
//console.log(username,password)
try{
// HTTP Request
const response = await fetch('/signup',{
method:'POST',
headers:{'Content-Type':'application/json'},
body:JSON.stringify({username,password})//JSON.stringify() static method converts a JavaScript value to a JSON string
})
}catch(error){
console.log(error)
}
})
</script>
```
## JWT (Theory)
```
npm install jsonwebtoken
```


Create JWT token
sing({payload},private key,token attribute)
```javascript
//Create JWt token
const maxAge = 3 * 24 * 60 *60 // 3day
const createJWT = (userId)=>{
const token = jsonwebtoken.sign({userId},"meowheckerPrivateKey",{
expiresIn:maxAge
} ) //payload,private key, token attributes
return token
}
```
Sign up post function
jwt token 可以放在 signup function 裡面 -> Register 完可以給user 一個token !!
```javascript
//setting jwt token -> cookie
const jwtToken = createJWT(user._id)
response.cookie('JWT',jwtToken,{httpOnly:true,maxAge:3 * 24 * 60 * 60 *1000})
```


這樣 JWT token setting 就完成了
---
## Client Page 取得 the server json Data
透過fetch function 的return 送給 response varable
-> await response
```javascript=
<script>
const formElement = document.querySelector('form')
formElement.addEventListener('submit',async (event)=>{ //監聽submit 事件
event.preventDefault(event) //subit Defaut event -> refresh page
//get the vale from form
const username = formElement.username.value
const password = formElement.password.value
//console.log(username,password)
try{
const response = await fetch('/signup',{
method:'post',
body:JSON.stringify({username:username,password:password}), //JSON.stringify() static method converts a JavaScript value to a JSON string
headers:{'Content-Type':'application/json'}
}
)
//Parse the reponse(from Server) json data
const data = await response.json()
console.log(data)
}catch(error){
console.log(error)
}
})
</script>
```
Case 1

Case 2

## Show Error Message on signup page
-> get div class
document.
```javascript
//Error Elements
const usernameErrorElement = document.querySelector('.usernameError') //.className id-> #elementID
const passwordErrorElement = document.querySelector('.passwordError')
```
---
```javascript
// Show Error messages on sign page
if (data.errorsMessages){
usernameErrorElement.textContent = data.errorsMessages.username
passwordErrorElement.textContent = data.errorsMessages.password
}
```
---
### 如果Register Successful -> redirect -> homepage
```javascript
<script>
const formElement = document.querySelector('form')
//Error Elements
const usernameErrorElement = document.querySelector('.usernameError') //.className id-> #elementID
const passwordErrorElement = document.querySelector('.passwordError')
formElement.addEventListener('submit',async (event)=>{ //監聽submit 事件
event.preventDefault(event) //subit Defaut event -> refresh page(沒寫會出事)
// Reset Error Message !! //不然Error message 會在上面
usernameErrorElement.textContent= ""
passwordErrorElement.textContent= ""
//Get the vale from form
const username = formElement.username.value
const password = formElement.password.value
//console.log(username,password)
try{
const response = await fetch('/signup',{
method:'post',
body:JSON.stringify({username:username,password:password}), //JSON.stringify() static method converts a JavaScript value to a JSON string
headers:{'Content-Type':'application/json'}
}
)
//Parse the reponse(from Server) json data
const data = await response.json()
//console.log(data)
// Show Error messages on sign page
if (data.errorsMessages){
usernameErrorElement.textContent = data.errorsMessages.username
passwordErrorElement.textContent = data.errorsMessages.password
}
//console.log(data)
if (data.userId){
location.assign('/')//Navitage to URL
}
}catch(error){
console.log(error)
}
})
</script>
```
# Loggin User in
this 引用 userSchema login*() function 創建的 Instance
-> 在Database 下 設定 Statics login Authentication Logic
ser account unt Account exist
>比對password
>return user (findOne)
## Compare password
model/User.js
```javascript
userSchema.statics.login = async function(username,password){
const user = await this.findOne({username:username})
if (user){ //check UserName exist?
const authPassword = await bcrypt.compare(password, user.password) // hash(password) compare DB hashing password!
if (authPassword){ // check password
return user
}
throw Error("Incorrect Password")
}
throw Error("Incorrect Username")
}
```
## Setting login Action
authController.js
```javascript
module.exports.loginPost = async (request,response) => {
//拆成不同變數
const {username, password} = request.body //variable Name 要跟json key 一樣
try{
const user = await User.login(username,password) //user variable, getting from the database
response.status(200).json({userId:user._id})
}catch(error){
response.status(400).json({})
}
}
```
---
loggin user fornt-end Event Function
跟 Singn Event Function 相似
login.ejs
```javascript
<script>
//form Elements
const formElement = document.querySelector('form')
//Error Elements
const usernameErrorElement = document.querySelector('.usernameError') //.className id-> #elementID
const passwordErrorElement = document.querySelector('.passwordError')
formElement.addEventListener('submit',async (event)=>{ //監聽submit 事件
event.preventDefault(event) //subit Defaut event -> refresh page(沒寫會出事)
// Reset Error Message !! //不然Error message 會在上面
usernameErrorElement.textContent= ""
passwordErrorElement.textContent= ""
//Get the vale from form
const username = formElement.username.value
const password = formElement.password.value
//console.log(username,password)
try{
const response = await fetch('/login ',{
method:'post',
body:JSON.stringify({username:username,password:password}), //JSON.stringify() static method converts a JavaScript value to a JSON string
headers:{'Content-Type':'application/json'}
}
)
//Parse the reponse(from Server) json data
const data = await response.json()
//console.log(data)
// Show Error messages on sign page
if (data.errorsMessages){
usernameErrorElement.textContent = data.errorsMessages.username
passwordErrorElement.textContent = data.errorsMessages.password
}
//console.log(data)
console.log(data.userId)
if (data.userId){
location.assign('/adminpanel')//Navitage to URL
}
}catch(error){
console.log(error)
}
})
</script>
```

---
## login Error message & create JWT token
寫在HandlerError
現抓錯誤訊息-> 設定username 跟password ErrorMessage
AuthCotroller.js
```javascript
const handleErrors = (errorObj)=>{
//console.log(errorObj.message,errorObj.code)
let errorsMessages ={username:'',password:''}
console.log(errorObj.message)
//Username is not exist
if (errorObj.message === "Incorrect Username"){
errorsMessages.username = "that username is not Incroorect"
}
// password in not Incroorect
if (errorObj.message === "Incorrect Password"){
errorsMessages.password = "that username is not Incroorect"
}
//duplication error code
if (errorObj.code === 11000){
errorsMessages.username = "that username is already registred!!"
return errorsMessages
}
// validation errors
if(errorObj.message.includes('user validation failed')){
Object.values(errorObj.errors).forEach(({properties}) => {
console.log(properties)
errorsMessages[properties.path] = properties.message
})
}
//console.log(errorsMessages)
return errorsMessages // return error with json form
}
```
Error 格式

login.ejs
```javascript=
// Show Error messages on sign page
//console.log(data.errors)
console.log(data.errors.password)
if (data.errors){
usernameErrorElement.textContent = data.errors.username
passwordErrorElement.textContent = data.errors.password
}
```
### Create JWT when you login success !!
```javascript=
module.exports.loginPost = async (request,response) => {
//拆成不同變數
const {username, password} = request.body //variable Name 要跟json key 一樣
try{
const user = await User.login(username,password) //user variable, getting from the database
//Create JWT token After login
const jwtToken = createJWT(user._id) //console.log(user._id)
response.cookie('JWT',jwtToken,{httpOnly:true,maxAge:3 * 24 * 60 * 60 *1000})
response.status(200).json({userId:user._id})
}catch(error){
const errors = handleErrors(error)
response.status(400).json({errors})
}
}
```

# Protecting Routes
我們可以透過JWT 對routes 作保護
當User Access URL 會送 cookie 裡的 JWT 給 Server
我們就能去認JWT exist or be tampered
if 有問題就redirect 到 Login page
## Grab the token from the cookie(request)
透過有沒有抓到token 來判斷要不要處理 Router Reqeust
寫一個 request -->(middleware function (verify Token)) --> render page
middleware/authToken
```javascript
const jsonwebtoken = require('jsonwebtoken')
const requireAuthToken = (request, response , next)=>{
//get the request Token
const token = request.cookies.JWT // cookies."cookie Name"
//have token ?
if (token){
//verify the token
const authToken = jsonwebtoken.verify(token,'meowheckerPrivateKey',(error,decodedToken)=>{
if (error){
response.redirect("login")
}else {
console.log(decodedToken)
next() // verify successfully
}
})
}else{
//if not ->do>
response.redirect('/login')
}
}
//export
module.exports={requireAuthToken}
```
```javascript
//import
const {requireAuthToken} = require('./middleware/authMiddleware')
....
....
//Main web
app.get('/', (req, res) => res.render('home'));
app.get('/adminpanel', requireAuthToken , (req, res,) => res.render('adminpanel'));
```


笑死 有些website 會用URL or Method 來進行 Access Controll
這些都很好Bypass
# Loggin Use Out
我們沒辦法直接 delete 創一個新的 replace 他
```
module.exports.logout = (request,response)=>{
response.cookie('JWT','',{maxAge:1,httpOnly:true})
response.redirect('/')
}
```
## Checking the current User
`response.locals.user` 是一個在 Express 應用程式中使用的特殊變數。它被用於在請求的生命週期中存儲和共享數據。在這裡,它被用於存儲從資料庫中查詢到的用戶數據,以便在後續中間件或路由處理函式中訪問
middleware
```javascript
// middleware (next)
const injectUserDataToview = (request,response,next)=>{
const token = request.cookies.JWT
if(token){
//verify the token
const authToken = jsonwebtoken.verify(token,'meowheckerPrivateKey',async (errors,decodedToken)=>{
if (errors){
response.locals.user = null
next()
}else {
console.log(decodedToken)
let user = await User.findById(decodedToken.id) //grab user data from user
response.locals.user = user
next() // verify successfully
}
})
}else{
response.locals.user = null
next()
}
}
```
app.js
在所有URL router 下應用
```
const {requireAuthToken, injectUserDataToview} = require('./middleware/authMiddleware')
...
...
app.get('*',injectUserDataToview) // middleware (the check factor:JWT token )
```
再經經過這個Router middlware -> 他們透可以使用locals.user 這個變數資料(需JWT auth)
# Condiction Rendering
user = User(models).locals.user
透過 條件式來確認 user 是否存在
```
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="/styles.css">
</head>
<body>
<nav>
<h1><a href="/">Meow Hacker!!</a></h1>
<ul>
<% if(user) { %>
<li>Wellcome, <%= user.username %></li>
<li><a href="/logout" class="btn">Logout</a></li>
<% }else{ %>
<li><a href="/signup"class="btn">Sign Up</a></li>
<li><a href="/login"class="btn">Login</a></li>
<% } %>
</ul>
</nav>
```