FastAPI에서 Refresh Token 생성하는 구조
토요일.
지금만들고 있는 Toy Project는 Admin Site이기 때문에, 불특정 다수를 대상으로 하는 것도 아니고 통상적인 자그마한 수준의 트랜잭션을 감당 할 예정이라 모든 요청에 인증 및 권한체크를 하는 것으로 구상을 하고 있다.
인증 후 Token의 만료시간을 30분으로 잡고 있는데, 이 경우 계속 사용을 하면(===요청을 하면), 그 만료시간을 자동으로 늘려주려주는 방식의 구조를 만들려고 한다.
알아야 하는 사항
- login을 제외한 모든 요청은 인증체크와 권한체크가 되어야 한다는 전제이다.
- 모든 요청에 인증체크가 자동으로 되기 위해서 주입(injection)을 사용한다.
- 체크를 위한 값과 체크의 결과를 응답에 섞어서 받거나 내릴수 없기 때문에 request.header와 response.header를 사용한다.
- 해당 Request, Response 객체는 fastapi가 아니고 starlette에 있다.
- dependencies 선언에 파라메터를 넣을 수 없어서, 중간 함수가 하나 필요하다.
이 정도만 있으면, 구글링을 통해서 자신이 원하는 구조를 만들 수 있겠으나 코드를 좀 살펴보면.
Vue3, app의 instance를 다른 모듈에서 사용하기
토요일.
main.js에 구축했던 Google Login모듈을 리팩토링 하려고, google.service.js를 하나 만든것 까지는 좋았는데.
app.use(‘xx’)를 사용 할 수가 없었다.
알아야 하는 사항들
- main.js에서 만든 createApp()은 인스턴스를 생성한다.
- getCurrentInstance()를 사용해서 다른 모듈에서 접근이 가능하다.
- app을 끄집어 내기 위해서는 appContext를 사용해야 한다.
import { getCurrentInstance } from "vue";
function xx() {
const instance = getCurrentInstance();
// app에 접근해서 plugin을 주입한다.
instance.appContext.app.use(PluginObject, PluginOption);
}
Vue3 + script setup과 onMount()에 대한 생각
금요일.
Vue3를 살펴보면서 (아직 잘 몰라서 드는 생각이겠지만) 문서가 Vue2와 Vue3가 혼재하면서 아직 잘 모르는 사람이 찾기에는 어렵다는 생각을 많이 하게 된다.
사실은 Facebook Login기능을 붙이다가 전에 구현한 Google Login기능이 main.js에 덩그러니 있는것을 보고 모듈쪽으로 이동시키려고 시도하면서 시작된 것이었다.
Vue에서만 사용하는 단어인지는 모르겠지만 SFC(Single File Component)라는 단어가 있는데, 컴포넌트가 어딘가에 포함된 것이 아니고, 그 자체가 하나의 파일로 만들어져 있는 경우를 지칭한다고 생각된다.
어쨌거나, Vue3 혹은 Vue를 설명하는 많은 문서들에서 setup()내에 onMount()를 기술하고 있는 것을 볼 수 있는데, 내 경우에는 어찌해도 그녀석이 호출되지 않는 현상이 있었다.
FastAPI 요청 로그 생성하기
목요일.
FastAPI로 요청되는 것들에 대해서 로깅을 하려고 봤더니 한 방에 안되어 좀 찾아본다.
알아야 하는 사항들
- FastAPI 모든 요청에 끼워서 사용 할 수 있는 middleware 기능이 있으며, 사용방법이 아주 다양하다.
- middleware에서 request, response를 사용 할 수 있는데, starlette.requests 등이 필요하다.
- Python Logging을 사용하기 위해서 형식을 지정하는 formatter가 필요한데, FastAPI것도 있고 따로 만들어도 된다. 나는 별도 항목으로 정리하고자 해서 별도로 만들었다.
- Logging형식을 JSON으로 하고 싶어서 찾아보니
pythonjsonlogger라고 만들어 둔 것이 있다. - logging 객체를 함수안에서 만들면… 함수를 부를 때 마다 로그가 배수로 출력된다. 1 > 2 > 4 > 8 > ..?
설치
sudo pip install starlette-context
sudo pip install python-json-logger
main.py
from starlette.requests import Request
# 로그 객체 생성
logger = logging.getLogger()
logger.setLevel(로그래밸)
handler = logging.FileHandler(로그파일명)
handler.setFormatter(만들어진 포매터를 넣는다. pythonjsonlogger 깃헙 참조)
logger.addHandler(handler)
# Define Audit Log
@app.middleware('http')
async def audit_log(request: Request, call_next):
# ----------------------------------
# Next를 안부르면....!!!!
response = await call_next(request)
saveLog(logger, request, response)
return response
유심히 볼 부분은 audit_log 위쪽에 있는 어노테이션이다. 그리고 로거 객체는 함수 밖에서 만들어야 했고, saveLog()에 request와 response를 넘겨줘서 로깅할 내용을 꺼낼 수 있도록 한다.
Vite + Vue3 그리고 compilerOptions.isCustomElement
일요일.
eslint와 prettier설정관련 해서 결국 다른 템플릿으로 바꾸는 작업을 하고있었다.
거의 컴파일 오류를 다 잡고 개발에서 열심히 돌려보니 로직은 잘 돌아가는데 콘솔창에 Vue warning이 열심히 떨어지고 있다.
[Vue warn]: Failed to resolve component: ui5-button
If this is a native custom element, make sure to exclude it from component resolution via compilerOptions.isCustomElement.
이전 Template에서는 되고 새로운 Template에서는 안되는 것인가?
원래 이것은 vite.config.js에서 태깅을 해 뒀던 것이었다.
export default defineConfig({
plugins: [vue({
template:{
compilerOptions: {
isCustomElement: tag => tag.includes(`ui5`)
}
}
})],
...
결론부터 말하자면
개발빌드(npm run dev)에서는 발생하고, 운영빌드(npm run build)에서는 발생하지 않는다.
VSCode + .editorconfig 그리고 quote
토요일.
javaScript로 개발을 한다는 것이 (아마도) 엄청난 성장기라 그런지 개발환경에 대한 설정과 설정 그리고 설정을 하면서 배우고 또 배우는 상황인듯 하다.
기존에 만들고 있던 Toy Project에 eslint와 prettier를 적용하면서 잘될거라는 기대도 없었지만 역시나 역시나 멀쩡히 잘 되던 부분이 안되는 현상이 있어 몇 시간 삽질을 하다가 Pure한 Template을 다시 구해서 해보고 결국 설정이라는 생각을 하고 있다.
Vite + Vu3 + eslint + prettier + VSCode 설정의 대환장파티를 히루 종일 해 보고 남은 건.
Toy Projet를 만들면서 발생하는 일들을 기록 해 본다.
목요일.
Toy Projet를 만들면서 발생하는 일들을 기록 해 본다.
- 2022-01-24
Toy Project를 하나 만들기로 하고Front Template을 하나 정해서 GitHub에 커밋을 한다. 이것을 만들게 된 계기를 적어보면, 오라클 무료 인스턴스에 개인적으로 사용할 페이지를 올려 사용할 요량이었는데, 아무래도 인증이 필요해서 이것저것 Template을 찾아보는데, 영 마음에 드는것이 없다.
거기다 그 즈음 보기시작한 Facebook의 개발자 커뮤니티에 올라오는 질문글들을 보면서, 내가 경험한 것들을 조금은 가다듬어 세상에 넘겨줘야 겠다는 생각을 하게 된다. 누군가에게는 도움이 되기를 바라면서 말이다.
- 2022-02-01
구글에서 도메인을 하나 구입했다. 목적은 https를 적용하려면 도메인이 필요했기 때문이기는 한데.
도메인을 구입하고, 오라클 무료 인스턴스를 2개로 늘려서 작업 구성을 하면서 즐거워 하는 나를 발견한다. - halfenif.github.io: GitHub Page를 블로그로 사용하는건 계속 될 것이다. - filemover.enif.page: 주력으로 사용 할 개인적인 것들을 모아두는 인스턴스이다. - livedemo.enif.page: 인터넷상에 공개 할 목적으로 만든 데모 사이트이다. - demo.vvtui5.enif.page : Vite + Vue3 + Tailwind + SAP UI5로 만들어진 Demo 사이트이다.
- 2022-02-03 10:03:45
어제 밤까지 작업은 내용을 클라우드에 올리고 확인을 해보는데.. 뭔가 FastAPI 호출형식이 맞지 않는 오류가 발생한다. 뭐 그러려니 하는데.. 로그 보는 것이 영 불편하다. FastAPI 로그는 아니 정확하게는 Uviconr에서 로그를 생성하는 부분을 살펴보는데, 로깅에 대한dict항목만 찾아지는 것이 이게 뭔가 싶다. Stack Overflow에서 config file(아니 dict) sample을 구해서 넣어보니 동작은 하는데, 에러는 출력되지 않는다. log level이 debug가 아니고 trace로 바꾸자 좀 더 나오는데.. 뭔가 마음에 들지는 않는다. FaceBook Python 사용자 그룹에도움을 요청 해 보고 딴 짓을 한 참 하다가 다시 보는데. 내가 수정한 Header 값으로 요청을 하고 있지 않다. Vite에서 Build오류가 발생하고있어서, dist의 내용물들이 갱신이 안되고 있는 현상이 있다. IMG 항목중 URL이 Local인데 실제 파일이 없는 경우… 뭐 그럴수있지.
- 2022-02-03 23:04:26
로그를 보다가 보다가.. 결국 Nginx Log를 포맷을 수정했고, FileBeat로 Nginx Log를 긁어다가 MySQL로 넣기 위해 JOSN형태의 File로 떨어뜨렸었다가.. 아닌거 같아 Redis에 넣는 것 까지는 되었는데.
이 녀석을 다시 MySql로 넣기 위해서 Python AppScheduler를 보기 시작했고.
개발을 위해 WSL에 Redis를 설치하고 한참을 해 보는데.. 단순하게 생각해서 서버에서 긁어온(=화면에 출력된) 문자열을 WSL에 설치된 레디스에 넣었더니 Type Error가 나온다.
WSL에 Filebeat를 설치해서 Redis에 데이터를 생성하고 테스트해야 정확하다고 본다.
- 2022-02-09

DemoSite의 Logo를 변경했다.
뭔가를 만들려면 상하좌우 모두 두루 살펴서 받아들이는 사람이 이질감 없이 수용 할 수 있도록 준비 해 주는 것이 좋다는 생각이다.
로고는favicon.io라는 곳을 이용했다.
- 2022-02-11 13:46:53
그 사이 많은 일들이 있었다.
우선 ESLint를 적용하는 과정에서 처음 사용했던Template을 버리고, ESLint를 적용한Template로 갈아탔다. 이것은 시간이 매우 많이 소요되는 작업이었지만, 어설프게 웹 개발을 경험하는 것에서 이제 좀 본격적으로 개발 해 본다는 느낌을 가지게 해 주었다.
ESLint를 적용하는 과정에서 이것 저것 프로젝트를 만들다보니 GitHub의 레파지토리가 너무 중구난방이라는 생각이 들어서 전체에 대한 명명규칙을 만들고, 사용하지 않는것들은 삭제했다 - dev** : 개발중인 레파지토리이다. 나중에 demo*_로 Branch될 후보군이다. - demo__ : 인터넷상에 공개한 레파지토리이다. - test** : 테스트를 위해서 만들어본 레파지토리들이다. - toy** : 취미로 만들어보는 것들을 모아두었다.
- 2022-02-11 14:26:04
Vue에서 SVG를 설정하는 것에 대해 알게되었다.
이것의 시작은 ESLint 문법오류를 전부 잡고 Build를 시도하는 작업이었는데, 얼마전에 집어넣은 log.svg에 대한 경로를 찾지 못하는 오류가 나오면서 시작되었다.
어떤 문제를 직면했을 때 인간은 본능적으로 자신이 경험해 온 것을 기반으로 추론하고 행동하게 되었다.(당연한거다.)
이번에는 운이좋았던 것인지, 2시간만에 vite.config.js에서 svgLoader라는 단어를 발견하고, 오류가 나던 logo.svg대신 logo.png를 적용해 봄으로써 그 전까지 세웠던 가설과 추론이 모두 헛된것이었음을 증명하고 문제를 종료시킨다. 참.. 배울게 많다.
- 2022-02-12 14:48:44
Vue를 계속 적용 해 보면서 느끼는 생각은. Vue라는 것이 마치 거대한 무더기인데 거의 정리가 안 된 카오스같은. 그러다 보니 뭔가를 하나 하려면, 이것이 올바른 방법인지 아닌지 검토하고 판단하기 위해 오피셜 레퍼런스를 보지만, (사실 거기에 기술된 것이 정답이겠지만) 조금만 옆으로 응용하거나 더 나가려고 하면 걸리는 것들이 있다. 오늘은 이제까지 계속 생각하고 있던 main.js가 아닌 다른 곳에서 app instance에 접근하는 방법에 대해 검토를 해보니. appContext라는 단어를 찾기까지 시간이 그래도 많이 소요되었다. 이것은 결국 아직 (내가) JavaScript라는 것과 Vue가 프레임워크로서의 구성을 어떻게 해 놨는지에 대한 이해가 부족하다는 것을 반증한다는 생각이다. 한 2시간을 들여서 검토해보고 해결은 했다.
- 2022-02-15 09:21:29
CSS File을 삭제했다. 정확하게는 CSS가 필요한 부분의 Scope를 정하고, 해당 파일 내부의 Style로 설정하는 것으로 변경한 것이다.
이 Toy Project가 지향하는 바가 디지이너 없이 웹 개발경험이 없는 개발자가 간단한 사이트를 만드는 것인것 만큼, 디자인에 들어갈 Effort를 배제하라는 의미이기도 하다.
- 2022-02-15 23:12:58
Facebook 인증을 개발환경에서 만든 것을 운영으로 올리려다 보니,개인정보 처리방안과서비스 약관이 마음에 걸려.
인터넷을 찾아봤으나 마음에 드는 것이 없어 직접 작성했다.
Jekyll minima에 Counter 구성하기
화요일.
Jekyll minima thema에는 (당연히) 기본으로 제공하는 카운터가 없어서 하나 만들어 보기로 한다.
카운터의 원리를 여러가지 생각 해 볼 수 있겠으나, 특정 URL로 요청을 하면 카운터 이미지를 되돌로주는 방식이다.
카운팅을 하기 위해서는 카운텅 숫자를 보관 할 필요가 있기에.. 그건 DB를 사용하기로 하고, 남은건 어떻게 이미지를 만들것인가? 인데.
요즘은 SVG라는 걸출한 포맷이 보편화되었기에 이미지가 아니라 String을 반환하면 되기는 한다.
알아야 하는 사항
- Python에는 SVG용 라이브러리가 아주 많은거 같은데, svgwriter가 많이 사용되는 것 같다.
- Counter를 다른 사용자 혹은 다른 곳에서 사용되면 곤란하기 때문에, 요청 ORGIN을 반드시 체크해야한다.
from os.path import join
import svgwrite
def get_counter_by_uuid(uuid: str):
# DB에서 uuid로 기 등록된 카운터를 받아오거나 없으면 신규로 Insert한다.
row = sql_get_count_by_uuid(uuid)
if row:
countNumber = row['READ_COUNT']
countStr = f'Read Count : [{countNumber}]'
else:
countStr = 'Read Count Fail!'
# 카운터 파일 저장 할 폴더를 하나 만들어 두고
filename = join(COUNTER_DATA_FOLDER, f'{uuid}.svg')
# 드로잉을 하나 만들면서 크기를 넣어주고
dwg = svgwrite.Drawing(filename, (200,16))
# 문자열을 집어 넣는다
dwg.add(dwg.text(countStr, insert=(0, 13), fill='black'))
# 파일로 저장한다
dwg.save()
# 파일명을 반환한다
return filename
자 이제 SVG파일을 만들었으면.. (이걸 열어보면 HTML Element이다.) 반환을 해야 하는데, 사용하고 있는 FastAPI에는 FileResponse라는 아주 좋은 기능이 있다.
Server에 vite로 build한 것 배포하기
월요일.
만들고있는 Toy Project(빨리 이름을 지어줘야 겠다.)를 배포하려고 보니..
운영서버에 node가 설치될 이유가 있는가?
- 나는 정적인 웹서버로 Nginx를 사용 할 예정이니, Node가 필요한 상황은 아니다
# 그러니 NPM을 설치할 이유는 없어 보인다.
- 빌드결과물을 어떻게 Cloud에 올릴 것인가?
# 개발환경이나 혼자 막 쓰는 녀석이라면 Github을 통해서 간편하게 구성 할 수 있겠지만.
scp를 사용하기로 하고 설정을 한다.
# WSL에서
# Key는 미리 등록되어 있어야 한다. 사용자명은 ubuntu라고하면
# build된 결과물이 dist에 있고, cloud에서는 ~/temp/front에서 작업 할 것이다.
tar -cvzf dist.tar.gz dist/
scp -i ~/.ssh/키파일명 dist.tar.gz ubuntu@클라우드IP:temp/front/dist.tar.gz
# Cloud에서
# Nginx Root Folder에 대한 권한 작업은 되어 있어야 한다
# 다 지우고 넣는다. 잘 생각하자.
rm -rf dist
tar -xvf dist.tar.gz
rm -rf /var/www/html/*
cp -r ./dist/* /var/www/html
Key File을 매번 입력하기 싫으면, .ssh에 config File을 만들어두면 간편하게 사용 할 수 있기는 하다. (나는 그렇게 쓰고 있다.)
Oracle Cloud SSH Key & IP Table
월요일. 음력으로는 올해의 마지막 날.
무료로 제공해줘서 잘쓰고 있는 오라클 클라우드 인스턴스에 지금 만들고 있는 Toy Project를 올리려고 작업을 한다.
- 인스턴스를 만들 때 Private Key File을 받아놓자.
Public Key를 받아놓을 필요가 있을까?
아직까지는 그런 경우를 알지 못한다.
- Windows는 좀 그러니 WSL ssh folder에 밀어넣고 600으로 퍼미션을 변경 해 둔다. 안그러면 퍼미션관련 오류메시지를 볼 것이다.
//WSL에서
chmod 600 파일명
- default user는 Ubuntu의 경우 ubuntu이다. 자기 id 넣고, 순간 당황하지 말자.
이게 습관이라는 것이 참 무서운것이다.
뭐가 문제인지 인식하는데 시간이 좀 걸렸다.
- 방화벽 정책을 등록하고. (이미 다른 인스턴스가 있으면 함께 적용가능 하다.)
//Web Instance 관리화면에서
Networking >> Virtual Cloud Networks >> 해당VNC >> Subnet Details
여기 Security Lists에 추가한다.
- IP Table을 열어준다
//Instance에서
sudo iptables -I INPUT 5 -i ens3 -p tcp --dport 포트번호 -m state --state NEW,ESTABLISHED -j ACCEPT
- 재부팅시에도 설정을 유지하도록 하고 재부팅해서 확인한다. (확인은 반드시 실행해서 확인해보는..좀 위험한 발상이기는 하다만.)
//Instance에서
sudo apt install iptables-persistent
sudo netfilter-persistent save
sudo reboot