일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 스코프
- Background
- 디자인
- 레이아웃
- 리액트
- 카카오
- Express
- 네비게이션
- github
- Python
- Push
- AWS
- navigation
- 알림
- JS
- MongoDB
- EC2
- 배포
- 변수
- NATIVE
- React
- graphql
- scope
- 자바스크립트
- ubuntu
- 후기
- JavaScript
- 네이티브
- Notification
- 면접
- Today
- Total
어서와, 개발은 처음이지?
RESTful API에 Express Session 사용하기 본문
Session
세션은 클라이언트-서버 간 인증 정보를 기록하여, 특정 시간동안 인증절차 없이 사용자를 신뢰하고 서비스 이용에 편의와 여러가지 정보를 제공하는데에 사용됩니다.
세션이 생성되면 세션을 식별할 수 있는 id가 쿠키형태로 클라이언트에 저장되고, 서버에 요청할 때 이 id를 같이 전송합니다.
서버는 이 id로 각 클라이언트를 식별하고, 해당 클라이언트의 세션을 사용합니다.
<세션 생성 전>
<세션 생성 후>
Express Session
express-session은 express.js에서 세션관리 기능을 제공하는 미들웨어입니다.
간단한 사용법은 아래와 같습니다.
"use strict"; const express = require('express'); const session = require('express-session'); const app = express(); app.use(session({ secret: 'asdf123', resave: false, saveUninitialized: true, })); app.get('/', (req, res) => { res.send('hi '+req.session.name); }); app.get('/login', (req, res) => { req.session.name = 'yuddomack'; req.session.save(() => { res.redirect('/'); }) }); app.listen(3000,function(){ console.log(`Connect 3000 port!`) });
app.use(session())을 통해 req.session이라는 객체를 사용할 수 있으며, secret은 세션을 암호화 하기위한 키 값으로 임의의 값을 설정해주시면 됩니다. resave와 saveUninitialized는 크게 중요하지 않으니 기본 값을 사용합니다.
res.session에 key value를 달아주는 것으로 세션에 정보를 기록할 수 있습니다.
루트(/) 라우트에 접속했을때 req.session.name은 undefined를 나타내지만 /login 라우트에 접속하면 세션에 name이 생성되고, 클라이언트를 식별할 수 있는 id를 발행하여 쿠키로 response 해줍니다.
RESTful API와 Session
Express Session을 사용하던 중 API 요청에도 세션이 적용될까 하는 궁금증이 생겼습니다.
그 궁금증을 해결하기 위해
1.URL을 통한 평범한 요청
2.브라우저에서 fetch를 사용한 API 요청
3.React Native Application에서 fetch를 사용한 API 요청
상황을 테스트 해봤습니다.
일단 다음과 같이 라우트를 개설했습니다.
app.get('/login/browser', (req, res) => { req.session.name = 'browser man'; req.session.save(() => { res.send({result : 'hi '+req.session.name}); }) }); app.get('/login/api', (req, res) => { req.session.name = 'api man'; req.session.save(() => { res.send({result : 'hi '+req.session.name}); }) }); app.get('/login/react_native', (req, res) => { req.session.name = 'react man'; req.session.save(() => { res.send({result : 'hi '+req.session.name}); }) }); app.get('/buy', (req, res) => { if(req.session.name){ res.send({result:'thank you '+req.session.name}); } else { res.send({result:'login please'}); } });
<app.js>
1~3의 케이스가 정상 동작한다면, /buy를 요청했을때, thank you 라는 메세지가 나올 것 입니다.
1.URL을 통한 평범한 요청
보통의 웹 서비스처럼 브라우저에서 URL을 사용하여 서비스에 접근해봤습니다.
브라우저에서 URL을 통한 접근은 이상없이 동작하는 모습을 볼 수 있었습니다.
2.브라우저에서 fetch를 사용한 API 요청(부제 : express에서 크로스도메인 Access-Control-Allow-Origin 해결하기)
이번에는 html 파일을 만들어서 fetch를 상용하여 API로 세션을 생성해보겠습니다.
사실 이 Ajax라던지 이런 비동기 요청을 했을때, 쿠키가 생성되는지에 대한 의문이 들어서 2번 케이스를 실험하게 되었습니다.
추후에 react로 웹을 구현할 계획인데 만약 이 부분이 해결된다면 굳이 react route를 사용할 필요가 있을까 싶었습니다.
우선 html 파일을 아래와 같이 제작했습니다.
fetch는 localhost에서 동작 안하는 경우가 있어서 로컬 ip를 직접 입력했습니다.
<script> function reqLogin(){ fetch('http://192.168.xxx.xxx:3000/login/api') .then((response) => response.json()) .then((responseJson) => { resLogin.innerHTML = JSON.stringify(responseJson); }) .catch((error) => { resLogin.innerHTML = error; }); } function reqBuy(){ fetch('http://192.168.xxx.xxx:3000/buy') .then((response) => response.json()) .then((responseJson) => { resBuy.innerHTML = JSON.stringify(responseJson); }) .catch((error) => { resBuy.innerHTML = error; }); } </script> <body> <button onclick="reqLogin()">로그인 요청</button> <p id="resLogin">결과</p> <button onclick="reqBuy()">구매 요청</button> <p id="resBuy">결과</p> </body>
<api.html>
html 페이지를 실행하고 버튼을 눌러서 api를 요청하자, 장고로 api 만들때 보던 낯익은 메세지(Access-Control-Allow-Origin)가 보였습니다.
이를 해결하기 위해 cors 모듈을 설치하고 express에서 사용해주도록 했습니다.
const cors = require('cors'); const corsOptions = { origin: true, credentials: true }; app.use(cors(corsOptions));
<app.js>
그리고 다시 요청해보았습니다.
이번에는 로그인 요청(/login/api) 후 세션 id(connect.sid 쿠키)가 정상적으로 생성된 모습을 볼 수 있었습니다.
하지만 구매 요청(/buy)를 했을 때, thank you 메세지가 아닌 login please라는 결과를 보여줍니다.
무엇이 문제였을까요?
fetch를 통해 request할 때 이 쿠키 정보가 함께 전송되지 않아서 서버 입장에서는 식별자 정보를 가지고 있지 않은 사용자로 인식하기 때문이였습니다.
이를 해결하기 위해 fetch에 header정보를 설정해줍니다.
<script> const header ={ method: "GET", headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', 'Cache': 'no-cache' }, credentials: 'include' }; function reqLogin(){ fetch('http://192.168.219.113:3000/login/api', header) // 생략 } </script>
<api.html>
핵심은 credentials: 'include' 입니다.
include: Always send user credentials (cookies, basic http auth, etc..), even for cross-origin calls.라고 모질라 형님들이 말씀하셨습니다.
이제 정상적으로 동작하는 것을 볼 수 있습니다.
3.React Native Application에서 fetch를 사용한 API 요청
2번 케이스를 무사히 통과하자 React Native도 무난히 성공하였습니다.
아래는 테스트용 React Native 앱의 App.js 코드입니다.
import React, {Component} from 'react'; import {StyleSheet, Text, View, Button} from 'react-native'; type Props = {}; const header ={ method: "GET", headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', 'Cache': 'no-cache' }, credentials: 'include' }; export default class App extends Component<Props> { constructor(props){ super(props); this.state = { login:"", buy:"", }; } _reqLogin(){ fetch('http://192.168.xxx.xxx:3000/login/react_native', header) .then((response) => response.json()) .then((responseJson) => { this.setState((prevState, props) => { return {login:JSON.stringify(responseJson)} }) }) .catch((error) => { this.setState((prevState, props) => { return {login:JSON.stringify(error)} }) }); } _reqBuy(){ fetch('http://192.168.xxx.xxx:3000/buy', header) .then((response) => response.json()) .then((responseJson) => { this.setState((prevState, props) => { return {buy:JSON.stringify(responseJson)} }) }) .catch((error) => { this.setState((prevState, props) => { return {buy:JSON.stringify(error)} }) }); } render() { return ( <View style={styles.container}> <Text style={styles.welcome}>Session Test</Text> <Button title="로그인 요청" onPress={this._reqLogin.bind(this)}/> <Text>{this.state.login || "결과"}</Text> <Button title="구매 요청" onPress={this._reqBuy.bind(this)}/> <Text>{this.state.buy || "결과"}</Text> </View> ); } } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#F5FCFF', }, welcome: { fontSize: 20, textAlign: 'center', margin: 10, }, });
API 요청과 세션이 정상적으로 동작하는 모습을 볼 수 있습니다.
마무리
기존의 웹 서비스 처럼 브라우저로 접근하는 요청 뿐만아니라 API 에서도 세션이 사용되는 것을 알 수 있었습니다.
다만, 인증 정보를 유지하기 위해서는 cors 모듈과 credentials 설정을 통해 크로스 도메인 문제와 쿠키 정보를 전달하도록 해야 합니다.
이로써 비동기 API 요청에서도 세션 검증을 통해 정보 제공을 제한할 수 있겠습니다.
'Node' 카테고리의 다른 글
브라우저 onfocus시에 react server component revalidate 하기 (1) | 2024.04.28 |
---|---|
카카오 오픈빌더와 외부 API 연동(feat.Nodejs) (12) | 2020.03.16 |
Nodejs로 AWS Polly(text to speech) 사용하기 (0) | 2019.03.01 |
카카오 플러스친구 API 연동 with Node.js (1) | 2018.07.29 |