π Token ?
νλ‘κ·Έλλ° μΈμ΄μμμ token
λ¬Έλ²μ μΌλ‘ λ μ΄μ λλ μ μλ κΈ°λ³Έμ μΈ μΈμ΄ μμλ₯Ό λ§νλ€.
ν€μλλ μ°μ°μ, ꡬλμ λ±μ΄ token μ΄ λ μ μλ€.
λ€νΈμν¬μμμ token
λ€νΈμν¬λ₯Ό λ°λΌ λμλ€λλ μνΈνλ λΉνΈμ΄μ΄λ€.
κ° λ€νΈμν¬μλ μ€μ§ νλμ token λ§ μ‘΄μ¬νλ―λ‘ 2κ° μ΄μμ μ»΄ν¨ν°κ° λμμ λ©μΈμ§λ₯Ό μ μ‘ν κ°λ₯μ±μ μ¬μ μ μ°¨λ¨νλ€.
보μμμ€ν μμμ token
ν¬λ λ§ μΉ΄λ ν¬κΈ°μ μμ μ₯μΉλ₯Ό λ§νλ€.
μ¬μ©μκ° μ²μμ μνΈλ₯Ό μ λ ₯νλ©΄, μΉ΄λλ λ€νΈμν¬μ μ μν μ μλ IDλ₯Ό μμλ‘ λ³κ²½ν΄κ°λ©° νμν΄μ€λ€.
--> 곡μ μμ μ κ·Όμ λν λκΈ°νλ₯Ό 보μ₯νκΈ° μν΄ μ¬μ©λλ μΆμμ μΈ κ°λ μ΄λ€.
--> token μ κ°μ§ μ¬λμ΄λΌλ©΄ λꡬλ νΉμ μμμ λ°°νμ μ κ·Όμ΄ νμ©λκ³ (μ νμ μΌλ‘) κ·Έκ²μ ν΅μ ν μ μλ κΆνμ κ°κ²λλ€.
π Token-based Authentication λμ κ³Όμ ?
π session κΈ°λ° μΈμ¦κ³Ό token κΈ°λ° μΈμ¦ κ° ( ꡬνμ μμ΄ ) μ°¨μ΄μ μ΄ μλ€λ©΄ ?
session κΈ°λ° μΈμ¦μ
π express-session λͺ¨λμ μ¬μ©νμ λ cookie λ₯Ό μ½μ΄μ€κ±°λ μΆκ°ν λ λ³ λ€λ₯Έ μ€μ μ΄ νμνμ§ μμλ€.
" μΈμ μΏ ν€ " κ°λ μ΄λΌ, cookie μ κΈ°λ³Έκ°μ 미리 μ€μ ν΄μ€ μ μμλ€.
token κΈ°λ° μΈμ¦μ
μΈμ κΈ°λ°κ³Ό λ§μ°¬κ°μ§λ‘ cookie λ₯Ό νμ©νκΈ΄ νμ§λ§, μλ² λ΄μ μΈμ¦μ μν 곡κ°μ λ°λ‘ ν λΉνμ§ μλλ€.
token μ μνΈννκ±°λ 볡νΈννλ μμ€ν λ§ μμΌλ©΄ λκΈ° λλ¬Έμ΄λ€.
--> ν΄λΌμ΄μΈνΈλ¨μ cookie λ₯Ό κ΄λ¦¬ν΄μ€ νμμ±μ΄ μμ΄μ§ !-!
κ·Έλμ μ΄λ°μλ μΏ ν€λ₯Ό μμκ² μ½μ΄μ€λ μμ , νλ°μλ μΏ ν€λ₯Ό μμκ² λ³΄λ΄λ λ°©λ² λ±μ΄ μΆκ°λλ€ γ γ
const express = require('express');
const cookieParser = require('cookie-parser');
const app = express();
app.use(cookieParser());
// μμ μ½λ
app.get('/', function(req, res){
// Cookies that have not been signed
console.log('Cookies: ', req.cookies);
// Cookies that have been signed
console.log('Signed Cookies: ', req.signedCookies);
})
μμ²μ΄ λ€μ΄μ€λ©΄ DBμμ μΌμΉνλ μ 보λ₯Ό μ°Ύκ³ , token μ μμ±ν ν μΏ ν€μ λ΄μ μλ΅μ 보λΈλ€.
// controller/users/login.js
// DBμμ λΆλ¬μ¨ Users TABLE
const { Users } = require('../models'); // (model/index.js)
// ν ν°μ μμ±νκ³ νμ±νλ λͺ¨λ
const jwt = require('jsonwebtoken');
// ν ν° μμ±,νμ±ν λ νμν ν€ κ°λ€ λΆλ¬μ¬ λ μ¬μ©νλ λͺ¨λ
require('dotenv').config();
module.exports = (req, res) => {
// Users ν
μ΄λΈμμ μμ²κ³Ό μΌμΉνλ μ 보λ₯Ό query ν΄μ¨λ€.
Users.findOne({
where: { userId: req.body.userId, password: req.body.password }
})
.then((data) => {
// λ±λ‘λ νμμ΄ μλλΌλ©΄ μ κ·Ό λΆκ°νλ€κ³ μλ €μ€λ€.
if(!data){
res
.status(400)
.json({
data: null,
message: 'not authorized'
});
}
else{
// λ±λ‘λ νμμ΄λΌλ©΄ access-token κ³Ό refresh-token μ μμ±νλ€.
const payload = data.dataValues;
delete payload.password;
// jwtλͺ¨λμ ν΅ν΄ ν ν° μμ±
const access_token = jwt.sign(payload, process.env.ACCESS_SECRET, { expiresIn: 60 * 60 });
const refresh_token = jwt.sign(payload, process.env.REFRESH_SECRET);
// access-token μ response body μ λ£κ³ ,
// refresh-token μ headerμ cookie μ λ£μ΄ λ°ννλ€.
res
.append('Set-Cookie',
`refreshToken=${refresh_token};
SameSite=none;
Secure;
HttpOnly`)
.status(200)
.json({
data: {
accessToken: access_token
},
message: 'ok'
})
}
})
};
DB μμ μνλ μ 보λ₯Ό κ°μ Έμ JWT μ μμ±ν΄μ ν΄λΌμ΄μΈνΈ λ¨μ token μ λ겨μ€λ€.
// controller/users/accessTokenRequest.js
// DBμμ λΆλ¬μ¨ Users TABLE
const { Users } = require('../models'); // (model/index.js)
// ν ν°μ μμ±νκ³ νμ±νλ λͺ¨λ
const jwt = require('jsonwebtoken');
// ν ν° μμ±,νμ±ν λ νμν ν€ κ°λ€ λΆλ¬μ¬ λ μ¬μ©νλ λͺ¨λ
require('dotenv').config();
module.exports = async(req, res) => {
// request headerμ authorization κ°μ΄ λ΄κΈ΄λ€λ κ±Έ νμΈν μ μλ€.
const authorization = req.headers['authorization'];
// μΈκ°λ ν ν°μ΄ μλ€λ©΄,
if(!authorization){
// λ±λ‘λ νμ μ 보λ₯Ό μ½μ΄μ¬ μ μμΌλ―λ‘, μΉμΈμ κ±°λΆνλ€.
res.status(400).json({ data: null, message: 'invalid access token' });
}
else{
// μΈκ°λ ν ν°μ΄ μλ€λ©΄
const token = authorization.split(' ')[1];
// ν ν°μ 볡νΈννμ¬ μμνμ dataλ‘ λ³΅κ΅¬μν¨λ€.
const data = jwt.verify(token, process.env.ACCESS_SECRET);
// 볡ꡬλ data μ μΌμΉνλ μ¬μ©μ μ 보λ₯Ό μ°Ύλλ€.
const userInfo = await Users.findOne({
where: { userId: data.userId },
});
// λ§μ½ μ¬μ©μ μ λ³΄κ° μ‘΄μ¬νμ§ μλλ€λ©΄
if(!userInfo){
// access-token μ κΈ°νμ΄ λ§λ£λμλ€λ μκΈ°μ΄λ―λ‘, λ°νλλ κ°μ μλ€.
res.status(403).json({ data: null, message: 'access token has been tempered' });
}
else{
// access-token μ΄ λ§λ£λμ§ μμκ³ && μ¬μ©μ μ λ³΄κ° μ‘΄μ¬νλ€λ©΄
const payload = userInfo.dataValues;
// λ―Όκ°ν μ 보λ μ§μ°κ³
delete payload.password;
// request body μ μ¬μ©μ μ 보λ₯Ό λ΄μ μλ΅νλ€.
res.status(200).json({ data: { userInfo: payload }, message: 'ok' });
}
}
};
λ‘κ·ΈμΈ ν νμμ 보λ₯Ό μ»μ λ authorization header μ λ΄κΈ΄ token μ 볡νΈννμ¬ DB μ μΌμΉνλ μ λ³΄κ° μλμ§, λ tokenμ΄ (μ¬κΈ°μλ access-token) λ§λ£λμ§λ μμλμ§ νμΈνμ¬ μΌμΉνλ μ 보λ₯Ό λ°ννλ€ !-!
// controller/users/refreshTokenRequest.js
// DBμμ λΆλ¬μ¨ Users TABLE
const { Users } = require('../models'); // (model/index.js)
// ν ν°μ μμ±νκ³ νμ±νλ λͺ¨λ
const jwt = require('jsonwebtoken');
// ν ν° μμ±,νμ±ν λ νμν ν€ κ°λ€ λΆλ¬μ¬ λ μ¬μ©νλ λͺ¨λ
require('dotenv').config();
module.exports = (req, res) => {
const refreshToken = req.cookies.refreshToken;
if(!refreshToken){
res
.status(403)
.json({
data: null,
message: 'refresh token not provided'
});
}
else{
jwt.verify(refreshToken, process.env.REFRESH_SECRET,
async function(err, data){
if(err){
res
.status(400)
.json({
data: null,
message: 'invalid refresh token, please log in again'
});
}
else{
const userInfo = await Users.findOne({
where: { userId: data.userId },
});
if(!userInfo){
res
.status(401)
.json({
data: null,
messgae: 'refresh token has been tempered'
});
}
else{
const payload = userInfo.dataValues;
delete payload.password;
const access_token = jwt.sign(payload, process.env.ACCESS_SECRET, { expiresIn: 60 * 60 });
res
.status(200)
.json({ data: {
accessToken: access_token,
userInfo: payload
},
message: 'ok'
});
}
}
}
)
}
};
refresh-token μ μ²λ¦¬νλ λ‘μ§μΈλ°, κ°μ μ μ¬μ§κ° νμν΄λ³΄μΈλ€ ..!
refresh-token μ access-token μ΄ λ§λ£λμμ λ μλ²μμ νμΈ ν μλ‘μ΄ access-token μ λ°κΈν΄μ£ΌκΈ° μν΄ μ‘΄μ¬νλ€.
μΈμ»¨λ νμΈ ν ν°μ΄λΌκ³ μκ°νλ©΄ μ’μλ―
'Back-end > Server' μΉ΄ν κ³ λ¦¬μ λ€λ₯Έ κΈ
Session & Session-based Authentication μ λμ κ³Όμ (0) | 2021.11.25 |
---|
λκΈ