main.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  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, Authorize: AuthJWT = Depends()):
  102. try:
  103. Authorize.jwt_required()
  104. except Exception as e:
  105. print(e)
  106. return RedirectResponse('/login')
  107. # current_user = Authorize.get_jwt_subject()
  108. return templates.TemplateResponse(name='tower.html', context={'request': request})
  109. @app.get('/optim', response_class=HTMLResponse)
  110. async def optim(request: Request, Authorize: AuthJWT = Depends()):
  111. try:
  112. Authorize.jwt_required()
  113. except Exception as e:
  114. print(e)
  115. return RedirectResponse('/login')
  116. # current_user = Authorize.get_jwt_subject()
  117. return templates.TemplateResponse(name='optim.html', context={'request': request})
  118. @app.get('/vibration', response_class=HTMLResponse)
  119. async def vibration(request: Request, Authorize: AuthJWT = Depends()):
  120. try:
  121. Authorize.jwt_required()
  122. except Exception as e:
  123. print(e)
  124. return RedirectResponse('/login')
  125. # current_user = Authorize.get_jwt_subject()
  126. return templates.TemplateResponse(name='vibration.html', context={'request': request})
  127. @app.get('/history', response_class=HTMLResponse)
  128. async def history(request: Request, Authorize: AuthJWT = Depends()):
  129. try:
  130. Authorize.jwt_required()
  131. except Exception as e:
  132. print(e)
  133. return RedirectResponse('/login')
  134. # current_user = Authorize.get_jwt_subject()
  135. return templates.TemplateResponse(name='history.html', context={'request': request})
  136. @app.get('/device', response_class=HTMLResponse)
  137. async def device(request: Request, Authorize: AuthJWT = Depends()):
  138. try:
  139. Authorize.jwt_required()
  140. except Exception as e:
  141. print(e)
  142. return RedirectResponse('/login')
  143. # current_user = Authorize.get_jwt_subject()
  144. return templates.TemplateResponse(name='device.html', context={'request': request})
  145. @app.get('/system', response_class=HTMLResponse)
  146. async def system(request: Request, Authorize: AuthJWT = Depends()):
  147. try:
  148. Authorize.jwt_required()
  149. except Exception as e:
  150. print(e)
  151. return RedirectResponse('/login')
  152. # current_user = Authorize.get_jwt_subject()
  153. return templates.TemplateResponse(name='system.html', context={'request': request})
  154. # Login funtion part
  155. def check_user_exists(username):
  156. db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/aaron_testdb?charset=utf8mb4')
  157. if int(next(iter(db.query('SELECT COUNT(*) FROM aaron_testdb.users WHERE userName = "'+username+'"')))['COUNT(*)']) > 0:
  158. return True
  159. else:
  160. return False
  161. def get_user(username: str):
  162. """ 取得使用者資訊(Model) """
  163. db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/aaron_testdb?charset=utf8mb4')
  164. if not check_user_exists(username): # if user don't exist
  165. return False
  166. user_dict = next(
  167. iter(db.query('SELECT * FROM aaron_testdb.users where userName ="'+username+'"')))
  168. user = models.User(**user_dict)
  169. return user
  170. def user_register(user):
  171. db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/aaron_testdb?charset=utf8mb4')
  172. table = db['users']
  173. user.password = get_password_hash(user.password)
  174. table.insert(dict(user))
  175. def get_password_hash(password):
  176. """ 加密密碼 """
  177. return pwd_context.hash(password)
  178. def verify_password(plain_password, hashed_password):
  179. """ 驗證密碼(hashed) """
  180. return pwd_context.verify(plain_password, hashed_password)
  181. def authenticate_user(username: str, password: str):
  182. """ 連線DB,讀取使用者是否存在。 """
  183. db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/aaron_testdb?charset=utf8mb4')
  184. if not check_user_exists(username): # if user don't exist
  185. return False
  186. user_dict = next(iter(db.query('SELECT * FROM aaron_testdb.users where userName ="'+username+'"')))
  187. user = models.User(**user_dict)
  188. if not verify_password(password, user.password):
  189. return False
  190. return user
  191. def create_access_token(data: dict, expires_delta: Optional[timedelta] = None):
  192. """ 創建token,並設定過期時間。 """
  193. to_encode = data.copy()
  194. if expires_delta:
  195. expire = datetime.utcnow() + expires_delta
  196. else:
  197. expire = datetime.utcnow() + timedelta(minutes=15)
  198. to_encode.update({"exp": expire})
  199. encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
  200. return encoded_jwt