728x90

안녕하세요! 오늘은 현재 구글에서 가장 인기 있는 키워드 중 하나인 "엔화"에 대해 알아보려고 합니다. 엔화는 일본의 통화 단위로, 금융 시장 및 경제에 대한 많은 관심을 끌고 있습니다. 지금부터는 엔화에 관한 최신 동향과 시장 전망을 살펴보겠습니다.

1. 엔화의 강세와 약세: 최근 엔화의 환율은 변동이 심하여 시장 참가자들에게 큰 관심을 불러일으켰습니다. 엔화가 강세를 보일 때에는 일본 경제의 안정성과 성장에 대한 신뢰가 반영되는 것으로 해석됩니다. 반면 약세일 때에는 경제적 불안 요인이나 국제적인 요인으로 인한 영향이 큽니다.

2. 엔화와 경제 정책의 관계: 엔화의 가치는 일본의 경제 정책과 밀접한 연관이 있습니다. 특히 일본은 경기 부양을 위해 통화 가치 조정 등의 정책을 시행할 때 엔화의 가치 변동이 큰 영향을 미칩니다.

3. 엔화와 국제 무역: 일본은 세계 경제에 큰 영향을 미치는 대형 수출국 중 하나입니다. 그러므로 엔화의 가치 변동은 국제 무역에서도 중요한 영향을 미칩니다. 엔화의 강세는 수출에 대한 경쟁력을 약화시키고, 약세는 수출 경쟁력을 향상시킵니다.

4. 엔화의 미래 전망: 전문가들은 엔화의 미래에 대해 다양한 의견을 제시하고 있습니다. 일부는 엔화의 강세가 지속될 것이라고 예측하며, 다른 일부는 엔화의 하락이 예상되는 경향을 보입니다. 따라서 투자자들은 시장의 변동성을 고려하여 엔화에 대한 투자 전략을 수립해야 합니다.

728x90
728x90
npm init

Webpack Install


npm i -D webpack webpack-cli webpack-dev-server @webpack-cli/generators html-webpack-plugin 

init

npx webpack init

Typescript Install


npm i -D typescript ts-loader

init

npx tsc --init

Babel Install

npm i -D @babel/core @babel/preset-env babel-loader
728x90

'study > 프론트엔드' 카테고리의 다른 글

[이것저것 코드] .eslint.js => no-unused-vars  (0) 2023.02.09
[CSS] 텍스트 ... 처리  (0) 2022.09.07
호이스팅  (0) 2022.07.22
728x90

Type assert

 

function example(e:FormEvent){
	const target:HTMLElement = e.target as HTMLElement
}
728x90
728x90

[관리자페이지] Admin Page - Admin - SiginIn 페이지 #7 Token 체크 리다이렉트


관리자 페이지 화면 구현은 Nextjs를 사용합니다.

Nextjs를 사용하기 위해서는 node.js를 설치해야합니다.

https://nodejs.org/en/download

설치 후에는 npx create-next-app@latest 를 이용해서 nextjs 프로젝트를 생성해 줍니다.

npx create-next-app@latest

app router를 사용합니다.
프로 젝트 생성 후에는 app 디렉토리에 admin과 signin 디렉토리를 각각 생성해 줍니다.

.
┗src
   ┗app
     ┗ admin
         ┗ page.tsx
     ┗ signin
         ┗ page.tsx

각 디렉토리에 page.tsx를 생성해 주고 간단한 텍스트 작성 후에

npm run dev

로 실행시킵니다.

// src/app/admin/page.tsx

export default function Admin(){
    return <>admin</>
}

// src/app/Signin/page.tsx
export default async function Signin() {
    return <>Sign In</>
}

 

 

Nextjs middleware를 사용해서 admin page로 접속 시 1) 토큰이 없거나, 2) 토큰이 있지만 만료 되었을 경우 SignIn 페이지로 이동하는 로직을 작성해 줍니다.

토큰은 cookie에 있고

먼저 토큰을 체크하는 로직을 작성해 줍니다.

 

 

https://nextjs.org/docs/app/building-your-application/routing/middleware

 

Routing: Middleware | Next.js

Learn how to use Middleware to run code before a request is completed.

nextjs.org

//src/middleware.ts
import {NextRequest, NextResponse} from 'next/server'

export function middleware(request: NextRequest) {

    if (request.nextUrl.pathname.startsWith('/admin')) {
        const cookie =request.cookies.get("token");
        if(!cookie){
            return NextResponse.redirect(new URL('/signin', request.url))
        }
    }


}

export const config = {
    matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)',],
}

 

728x90
728x90

pip install 로 mariadb 를 설치시 발생할수 있는 에러

This error typically indicates that MariaDB Connector/C, a dependency which      must be preinstalled, is not found.

 

 

sudo apt install libmariadb3 libmariadb-dev

 

 

https://askubuntu.com/questions/1438002/mariadb-connector-c-is-not-installed

728x90
728x90

[관리자 페이지] Admin Page - 회원가입 구현하기 #6 JWT 토큰 발행


https://jwt.io/

[JWT.IO

JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties.

jwt.io](https://jwt.io/)

아이디 / 패스워드로 사용자 로그인을 성공하면 jwt 를 발급합니다.

accessToken, refreshToken 2개를 발급합니다.

import jwt
from datetime import datetime, timedelta
from dotenv import load_dotenv
import os

load_dotenv(os.path.join(os.path.dirname(__file__), "..", "..", ".env"))


class CommonUtils:
    ACCESS_TOKEN_EXPIRE = os.getenv("ACCESS_TOKEN_EXPIRE")
    REFRESH_TOKEN_EXPIRE = os.getenv("REFRESH_TOKEN_EXPIRE")
    SECRET_KEY = os.getenv("SECRET_KEY")
    @staticmethod
    def create_token(user_info):
        today = datetime.now()

        access_token_expire_time = today + timedelta(seconds=float(CommonUtils.ACCESS_TOKEN_EXPIRE))
        refresh_token_expire_time = today + timedelta(seconds=float(CommonUtils.REFRESH_TOKEN_EXPIRE))

        access_token_payload = {"iat": today, "iss": "hiio420.com", "exp": access_token_expire_time,
                                "sub": "Access Token",
                                "userId": user_info.id}
        access_token = jwt.encode(access_token_payload, "secret", algorithm="HS256")
        refresh_token_payload = {"iat": today, "iss": "hiio420.com", "exp": refresh_token_expire_time,
                                 "sub": "Refresh Token",
                                 "userId": user_info.id}
        refresh_token = jwt.encode(refresh_token_payload, CommonUtils.SECRET_KEY, algorithm="HS256")
        return {"access_token": access_token, "refresh_token": refresh_token}

.env 파일을 사용합니다.

.env 파일에는 token의 만료 시간과 토큰 발행에 사용할 시크릿 문자열이 있습니다.

유틸을 만든 이유는 나중에 이부분만 다른 프로젝트에도 사용될 수 있지 않을까하는 생각에 만들었습니다.


## UserService class
...
 
    def get_token(self, user_info: UserModel) -> TokenModel:
        token = CommonUtils.create_token(user_info)
        return TokenModel(accessToken=token["access_token"], refreshToken=token["refresh_token"])

UserService에 get_token을 만들고 user_info를 파라미터로 전달합니다.
get_token은 TokenModel을 반환합니다.

from pydantic import BaseModel, Field


class TokenModel(BaseModel):
    accessToken: str = Field("", title="Access Token")
    refreshToken: str = Field("", title="Refresh Token")

@api_main.post("/signin",response_model=TokenModel)
def signin(user: UserWithPasswordModel):
    user: UserModel = userService.sign_in(user)
    return userService.get_token(user)

728x90
728x90

sqlAlchemy 

query.one() -> query.first()

728x90
728x90

[관리자 페이지] Admin Page - 회원가입 구현하기 #5 비밀번호 체크


유저의 id와 암호환 된 password를 DB에 저장했습니다.
이제 유저가 로그인하기 위해 id와 password를 post로 넘기면 해당 id와 password를 가진 user를 찾아 반환합니다.

db model 인 User classdp validate_password를 정의해 줍니다.


class User(Base):
    __tablename__ = "USER"
    __table_args__ = {
        'comment': 'USER TABLE'
    }
    id = Column("USER_ID", String(20), primary_key=True, comment="USER ID")
    password = Column("PASSWORD", String(120), nullable=False, comment="USER PASSWORD")

    def validate_password(self, password):
        return bcrypt.checkpw(password.encode("utf-8"), self.password.encode("utf-8"))

bcrypt의 checkpw를 통해서 encode된 password와 db에서 가져온 password를 비교해 True / False를 반환합니다.

UserService에 sign_in이라는 메소드를 만들어 줍니다.


    def sign_in(self, user: UserWithPasswordModel) -> UserModel:

        # select user by id
        selected_user: Optional[User] = self.select_user_by_id(user.id)
        if selected_user is None:
            raise HTTPException(status_code=404, detail="User does not exist")

        # valid passwrod
        is_password_ok = selected_user.validate_password(user.password)
        if not is_password_ok:
            raise HTTPException(status_code=404, detail="Password incorrect")

        return UserModel(**selected_user.__dict__)

User가 없을 경우 404 / password가 맞지않을 경우 404를 에러가 발생하고,

모두 통과하면 password 속성이 없는 UserModel을 반환합니다.

728x90
728x90

[관리자 페이지] Admin Page - 회원가입 구현하기 #4 비밀번호 암호화


사용자의 정보는 id 와 password입니다. 이 password를 DB에 입력하기 전에 암호화 해서 넣어 줍니다.

python에서 암호화 모듈은 bcrypt를 사용합니다.


pip install bcrypt

암호화 하기 이전에 UserMoodel을 2개의 class로 나누어 줍니다.
기존의 UserModel에 id만을 남기고 password는 UserWithPasswordModel class에 옮겨주고 이 class는 UserModel을 상속받습니다.


# api/models/user.py
from typing import Optional

import bcrypt
from pydantic import BaseModel, Field


class UserModel(BaseModel):
    id: Optional[str] = Field(None, description="user's id")

    class Config:
        from_attritues = True


class UserWithPasswordModel(UserModel):
    password: Optional[str] = Field(None, description="user's password")

    class Config:
        from_attritues = True

암호화를 실행하는 method를 UserWithPasswordModel에 정의합니다.

class UserWithPasswordModel(UserModel):
    password: Optional[str] = Field(None, description="user's password")

    class Config:
        from_attritues = True

    def hash_password(self):
        self.password = bcrypt.hashpw(self.password.encode("utf-8"), bcrypt.gensalt()).decode("utf-8")

hash password 메소드를 실행하면 UserWithPasswordModel에서 받은 password는 암호화 되어 집니다.

UserService insert_user 에 hash_password 메소드를 실행하는 코드를 추가합니다.


    def insert_user(self, user: UserWithPasswordModel) -> bool:
        try:
            user.hash_password()
            self.db.add(User(**user.dict()))
            self.db.commit()
            return True
        except Exception as e:
            self.db.rollback()
            return False

암호화된 비밀번호가 insert 된것을 볼 수 있습니다.

728x90
728x90

[관리자 페이지] Admin Page - 회원가입 구현하기 #3 Insert User Data


현재 user가 id와 password만 api에 제공하면 데이터가 insert 되야 합니다.

이 과정을 진행 하기 위해서는 sqlAlchemy에서 session을 얻어와 FastAPI DI를 이용해 실행되는 api method에 주입시켜 줘야합니다.

먼저 session을 얻어오는 함수를 core.py에 작성해 줍니다.

# database/core.py
from typing import Generator

from sqlalchemy import URL, create_engine
from sqlalchemy.orm import sessionmaker, Session

url = URL.create(drivername="mariadb+mariadbconnector", username="hiio420", password="...", host="...",
                 port="...", database="HIIO_ADMIN")

engine = create_engine(url)

SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

def get_db() -> Generator[Session, None, None]:
    with SessionLocal() as session:
        yield session

sessionmaker를 통해 SessionLocal을 정의하고 get_db 함수를 만들어 with 과 yield 를 이용해 session을 이용합니다.

https://docs.python.org/ko/dev/reference/expressions.html#yield-expressions

이제 signup과 signin 함수에 di를 하기 위해 파라미터 값으로 Depends를 이용해 넘겨 줍니다.

# api/api_main.py
from typing import Optional

from fastapi import APIRouter, Depends
from sqlalchemy import insert
from sqlalchemy.orm import Session

from api.models import UserModel
from database import get_db, User

api_main = APIRouter()


@api_main.post("/signin")
def signin(user:UserModel,session:Session = Depends(get_db)):
    return {"accessToken": "accessToken", "refreshToken": "refreshToken"}


@api_main.post("/signup")
def signup(user:UserModel,session:Session = Depends(get_db)):
    return {"message": "success"}

db에 user 정보를 저장하는 service 를 하나 만들어 줍니다.

.
┣━api
┣━database
┣━service
┃  ┣━__init__.py
┃  ┣━user.py

root 디렉토리에 service directory를 만들고 그안이 init 파일과 user 파일을 만들어 줍니다.

UserService class를 만들어 주는데 생성자로 db Genertor 객체를 받는(get_db)서비스를 만들어 주고
method로 insert_user를 정의해 줍니다.

# service/user.py
from typing import Generator

from sqlalchemy import insert
from sqlalchemy.orm import Session

from api.models import UserModel
from database import User


class UserService:

    def __init__(self, db: Generator[Session, None, None]):
        self.i = 0
        self.db = next(db)

    def insert_user(self, user: UserModel) -> bool:
        try:
            self.db.add(User(**user.dict()))
            self.db.commit()
            return True
        except Exception as e:
            self.db.rollback()
            return False

이제 __init__.py 에 UserService를 초기화 하여 userService 변수에 할당하고 all을 이용해서 다른 파일에서도 사용할 수 있게끔 해줍니다.

# service/__init__.py
from database import get_db
from .user import UserService

userService = UserService(get_db())

__all__ = ['userService']

api_main.py 파일의 signup 함수에 userSerivce의 insert_user를 호출합니다.

# api/api_main.py

from fastapi import APIRouter, Depends
from sqlalchemy.orm import Session

from api.models import UserModel
from database import get_db
from service import userService
api_main = APIRouter()


@api_main.post("/signin")
def signin(user: UserModel, session: Session = Depends(get_db)):
    return {"accessToken": "accessToken", "refreshToken": "refreshToken"}


@api_main.post("/signup")
def signup(user: UserModel):
    status = userService.insert_user(user)
    return {"message": f"Insert {status}"}

서버를 실행하고 docs 다시 접속 해봅니다.

 

데이터가 잘 된것을 볼 수 있습니다.

 

728x90

+ Recent posts