main.py 7.3 KB

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