main.py 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. # fastapi
  2. from fastapi import FastAPI, Request, Response, HTTPException, status, Depends
  3. from fastapi import templating
  4. from fastapi.templating import Jinja2Templates
  5. from fastapi.responses import HTMLResponse, RedirectResponse, JSONResponse
  6. from fastapi.middleware.cors import CORSMiddleware
  7. # static file
  8. from fastapi.staticfiles import StaticFiles
  9. # fastapi view function parameters
  10. from typing import List, Optional
  11. # path
  12. import os
  13. # time
  14. # import datetime
  15. from datetime import timedelta, datetime
  16. # db
  17. import dataset
  18. from passlib import context
  19. import models
  20. # authorize
  21. from passlib.context import CryptContext
  22. pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
  23. from jose import JWTError, jwt
  24. from fastapi_jwt_auth import AuthJWT
  25. from fastapi_jwt_auth.exceptions import AuthJWTException
  26. from fastapi.security import OAuth2AuthorizationCodeBearer, OAuth2PasswordRequestForm
  27. # app
  28. app = FastAPI()
  29. app.add_middleware(
  30. CORSMiddleware,
  31. allow_origins=["*"],
  32. allow_credentials=True,
  33. allow_methods=["*"],
  34. allow_headers=["*"],
  35. )
  36. SECRET_KEY = "df2f77bd544240801a048bd4293afd8eeb7fff3cb7050e42c791db4b83ebadcd"
  37. ALGORITHM = "HS256"
  38. ACCESS_TOKEN_EXPIRE_MINUTES = 3000
  39. pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
  40. #
  41. app.mount(path='/templates', app=StaticFiles(directory='templates'), name='templates')
  42. app.mount(path='/static', app=StaticFiles(directory='static'), name='static ')
  43. #
  44. templates = Jinja2Templates(directory='templates')
  45. @AuthJWT.load_config
  46. def get_config():
  47. return models.Settings()
  48. # view
  49. @app.get('/', response_class=HTMLResponse)
  50. async def index(request: Request):
  51. print(request)
  52. return templates.TemplateResponse(name='index.html', context={'request': request})
  53. @app.get('/login', response_class=HTMLResponse)
  54. async def login(request: Request):
  55. return templates.TemplateResponse(name='login.html', context={'request': request})
  56. @app.post("/login")
  57. async def login_for_access_token(request: Request, form_data: OAuth2PasswordRequestForm = Depends(), Authorize: AuthJWT = Depends()):
  58. db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/aaron_testdb?charset=utf8mb4')
  59. user = authenticate_user(form_data.username, form_data.password)
  60. if not user:
  61. raise HTTPException(
  62. status_code=status.HTTP_401_UNAUTHORIZED,
  63. detail="Incorrect username or password",
  64. headers={"WWW-Authenticate": "Bearer"},
  65. )
  66. access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
  67. access_token = create_access_token(
  68. data={"sub": user.username}, expires_delta=access_token_expires
  69. )
  70. table = db['users']
  71. user.token = access_token
  72. print(user)
  73. table.update(dict(user), ['username'])
  74. access_token = Authorize.create_access_token(subject=user.username)
  75. refresh_token = Authorize.create_refresh_token(subject=user.username)
  76. Authorize.set_access_cookies(access_token)
  77. Authorize.set_refresh_cookies(refresh_token)
  78. # return templates.TemplateResponse("home.html", {"request": request, "msg": 'Login'})
  79. return {"access_token": access_token, "token_type": "bearer"} # 回傳token給前端
  80. @app.get('/register', response_class=HTMLResponse)
  81. async def login(request: Request):
  82. return templates.TemplateResponse(name='register.html', context={'request': request})
  83. @app.post('/register')
  84. async def register(request: Request, form_data: OAuth2PasswordRequestForm = Depends()):
  85. user = models.User(**await request.form())
  86. print(form_data.username, form_data.password, user)
  87. # 密碼加密
  88. user.password = get_password_hash(user.password)
  89. # 存入DB
  90. db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/aaron_testdb?charset=utf8mb4')
  91. user_table = db['users']
  92. user_table.insert(dict(user))
  93. # 跳轉頁面至登入
  94. return templates.TemplateResponse(name='login.html', context={'request': request})
  95. @app.get('/home', response_class=HTMLResponse)
  96. async def home(request: Request):
  97. return templates.TemplateResponse(name='home.html', context={'request': request})
  98. @app.get('/tower', response_class=HTMLResponse)
  99. async def tower(request: Request):
  100. return templates.TemplateResponse(name='tower.html', context={'request': request})
  101. @app.get('/optim', response_class=HTMLResponse)
  102. async def optim(request: Request):
  103. return templates.TemplateResponse(name='optim.html', context={'request': request})
  104. @app.get('/vibration', response_class=HTMLResponse)
  105. async def vibration(request: Request):
  106. return templates.TemplateResponse(name='vibration.html', context={'request': request})
  107. @app.get('/history', response_class=HTMLResponse)
  108. async def history(request: Request):
  109. return templates.TemplateResponse(name='history.html', context={'request': request})
  110. @app.get('/device', response_class=HTMLResponse)
  111. async def device(request: Request):
  112. return templates.TemplateResponse(name='device.html', context={'request': request})
  113. @app.get('/system', response_class=HTMLResponse)
  114. async def system(request: Request):
  115. return templates.TemplateResponse(name='system.html', context={'request': request})
  116. # Login funtion part
  117. def check_user_exists(username):
  118. db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/aaron_testdb?charset=utf8mb4')
  119. if int(next(iter(db.query('SELECT COUNT(*) FROM aaron_testdb.users WHERE userName = "'+username+'"')))['COUNT(*)']) > 0:
  120. return True
  121. else:
  122. return False
  123. def get_user(username: str):
  124. """ 取得使用者資訊(Model) """
  125. db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/aaron_testdb?charset=utf8mb4')
  126. if not check_user_exists(username): # if user don't exist
  127. return False
  128. user_dict = next(
  129. iter(db.query('SELECT * FROM aaron_testdb.users where userName ="'+username+'"')))
  130. user = models.User(**user_dict)
  131. return user
  132. def user_register(user):
  133. db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/aaron_testdb?charset=utf8mb4')
  134. table = db['users']
  135. user.password = get_password_hash(user.password)
  136. table.insert(dict(user))
  137. def get_password_hash(password):
  138. """ 加密密碼 """
  139. return pwd_context.hash(password)
  140. def verify_password(plain_password, hashed_password):
  141. """ 驗證密碼(hashed) """
  142. return pwd_context.verify(plain_password, hashed_password)
  143. def authenticate_user(username: str, password: str):
  144. """ 連線DB,讀取使用者是否存在。 """
  145. db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/aaron_testdb?charset=utf8mb4')
  146. if not check_user_exists(username): # if user don't exist
  147. return False
  148. user_dict = next(iter(db.query('SELECT * FROM aaron_testdb.users where userName ="'+username+'"')))
  149. user = models.User(**user_dict)
  150. if not verify_password(password, user.password):
  151. return False
  152. return user
  153. def create_access_token(data: dict, expires_delta: Optional[timedelta] = None):
  154. """ 創建token,並設定過期時間。 """
  155. to_encode = data.copy()
  156. if expires_delta:
  157. expire = datetime.utcnow() + expires_delta
  158. else:
  159. expire = datetime.utcnow() + timedelta(minutes=15)
  160. to_encode.update({"exp": expire})
  161. encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
  162. return encoded_jwt