session 개념, im-sprint-auth-session 리뷰
세션(Session)이란?
- HTTP Session id를 식별자로 구별하여 데이터를 사용자의 브라우저에 쿠키형태가 아닌 접속한 서버 DB에 정보를 저장한다.
- 클라이언트는 HTTP Session id를 쿠키로 메모리 저장된 형태로 가지고 있다.
- 메모리에 저장하기 때문에 브라우저가 종료되면 사라지게 된다.
중요
서버가 client에 유일하고 암호화된 ID를 부여
중요 데이터는 서버에서 관리
서버에 접속 상태가 저장
신뢰할 수 있는 유저인지 확인이 가능
Cookie에 세션 아이디가 저장
세션의 흐름
1. 클라이언트가 서버에 Resource를 요청합니다.
2. 서버에서는 HTTP Request를 통해 쿠키에서 Session id를 확인을 한 후에 없으면
Set-Cookie를 통해 새로 발행한 Session-id 보냅니다.
3. 클라이언트는 HTTP Request 헤더에 Session id를 포함하여 원하는 Resource를 요청을 합니다.
4. 서버는 Session id를 통해 해당 세션을 찾아 클라이언트 상태 정보를 유지하며 적절한 응답을 합니다.
쿠키 vs 세션
세션의 단점
1. 기본적으로 세션은 서버 메모리에 저장하고 있다. 우리의 서버에 사용자가 많아지면 메모리의 일정부분을 항상 차지하고 있으므로 가용메모리의 양이 줄어들어 서버의 성능이 안좋아지게 된다.
2. 세션은 기존 쿠키를 완전 대체한게 아니기 때문에 쿠키를 사용한다. 쿠키는 XSS공격에 매우 취약하다. 세션은 쿠키를 여전히 사용하기에 쿠키의 한계를 그대로 가지고 있다.
express-session 기본 사용법
설치 $ npm install express-session
//api 불러오기
var session = require('express-session')
// Use the session middleware
app.use(session({ secret: 'keyboard cat', cookie: { maxAge: 60000 }}))
// Access the session as req.session
app.get('/', function(req, res, next) {
if (req.session.views) {
req.session.views++
res.setHeader('Content-Type', 'text/html')
res.write('<p>views: ' + req.session.views + '</p>')
res.write('<p>expires in: ' + (req.session.cookie.maxAge / 1000) + 's</p>')
res.end()
} else {
req.session.views = 1
res.end('welcome to the session demo. refresh!')
}
})
출처: https://github.com/expressjs/session#reqsession
공식문서 확인 잘하자
im-sprint-auth-session
server
urclass의 1,2번은 잘 읽고 따라한다.
1. 받은 인증서 두개를 서버 폴더에 옮겨놓고, 클라이언트에서도 써야하는데, 클라이언트 패키지제이슨에 서버폴더로 경로를 지정해 찾아도 안되었기에 복사붙여넣기로 클라이언트 폴더에도 넣어줬다.
2. cors와 session 옵션 설정하기
1) cors : 우리는 3가지의 options를 주어야 한다. origin(프론트 주소가 어디?), methods(어떤 요청만 받을건지), credentials
credentials는 Access-Control-Allow-Origin을 true로 만들어주는 옵션
2) session 옵션 설정: 우리가 채워야 할 곳은 5곳이다.
쿠키때 설명 한 것들이라 자세한 것은 생략
// TODO: express-session 라이브러리를 이용해 쿠키 설정을 해줄 수 있습니다.
app.use(
session({
secret: '@codestates',
resave: false,
saveUninitialized: true,
cookie: {
domain: FILL_ME_IN,
path: FILL_ME_IN,
maxAge: 24 * 6 * 60 * 10000,
sameSite: FILL_ME_IN,
httpOnly: FILL_ME_IN,
secure: FILL_ME_IN,
},
})
);
3. controller 서버구현
1) controller/login.js (POST /users/login) 로그인 구현
-req.body에 어떤 것이 들어오는지 확인 필수
- userInfo를 찾았다면 또 확인 필수
-없다면 400 날리고, 있다면 session에 session아이디를 저장하고, 데이터를 메세지와 함께 날려준다.
module.exports = {
post: async (req, res) => {
// userInfo는 유저정보가 데이터베이스에 존재하고, 완벽히 일치하는 경우에만 데이터가 존재합니다.
// 만약 userInfo가 NULL 혹은 빈 객체라면 전달받은 유저정보가 데이터베이스에 존재하는지 확인해 보세요
consoele.log(req.body);
const userInfo = await Users.findOne({
where: { userId: req.body.userId, password: req.body.password },
});
console.log(userInfo)
// 결과가 존재하는 경우 세션 객체에 userId가 저장되어야 합니다.
if (!userInfo) {
// your code here
res.status(400).send({
data: null,
message: 'not authorized'
});
} else {
// HINT: req.session을 사용하세요.
req.session.save(function () {
req.session.userId = userInfo.userId;
res.status(200).json({data:userInfo,message: 'ok'});
})
}
}
}
2) 로그아웃과 유저인포(Logout and userInfo)
로그아웃은 req.session.destory() 사용해야한다. 세션을 삭제하는 방법
유저인포는
(1) req.session.userId를 콘솔에 찍어보고 테스트 돌려본다.
(2) 세션값이 없다면 그에 맞는 메세지 전달
(3) 있을경우 Users.findOne해서 유저정보를 찾아준다.
(4) 유저정보가 없다면 상태400과 그에 맞는 메세지 전달
(5) 있다면 상태200과 유저정보와 메세지 'ok' 전달
Client
로그인
로그인 하면서 유저정보도 같이 가져온다. 로그인 상태까지 변경한다.
loginRequestHandler() {
// TODO: 로그인 요청을 보내세요.
//
// 로그인에 성공하면
// - props로 전달받은 함수를 호출해, 로그인 상태를 변경하세요.
// - GET /users/userinfo 를 통해 사용자 정보를 요청하세요
//
// 사용자 정보를 받아온 후
// - props로 전달받은 함수를 호출해, 사용자 정보를 변경하세요.
axios.post('https://localhost:4000/users/login', {userId: this.state.username,
password: this.state.password,}, //아이디와 비번을 같이 전달 params
//그럼 로그인 서버에서 필요한 데이터 전달 완료
{ 'Content-Type': 'application/json', withCredentials: true }) // 옵션 설정
.then((res) => {
this.props.loginHandler()
return axios.get('https://localhost:4000/users/userinfo', {
withCredentials: true,
});
})
.then((res) => {
let { userId, email } = res.data.data; //자바스크립트 최신문법 임
this.props.setUserInfo({
userId,
email,
});
})
.catch((err) => console(err));
}
스프린트 정리 끝--
중요하기에 다시한번
세션 기반 인증방식