---
title: 使用 FastAPI 及 MongoDB 建立登入 API
tags: 筆記
description:
---
## 開啟 MongoDB
**輸入連結後點擊 `Connect` ,進行連接。**

**新增 `Database` 以及 `Collection`。**

**資料表中的資料。**

## 建立 FastAPI
```python
import uvicorn
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from api.authentication import router as auth_router
def create_app ():
app = FastAPI()
# 允許指定源頭發起跨來源請求
origins = [
'http://localhost',
'http://localhost:3000'
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=['*'],
allow_headers=['*']
)
return app
app = create_app()
app.include_router(auth_router, prefix='/api')
if __name__ == '__main__':
uvicorn.run(app, host='127.0.0.1', port=8000)
```
## 驗證身分
### JWT token 加密
```python
import jwt
SECRET_KEY = 'kirito'
def generate_token (result: dict):
payload = {
'name': result['name'],
'role': result['role'],
'username': result['username'],
'password': result['password'],
'avatar': result['avatar']
}
token = encode(payload, SECRET_KEY, algorithm='HS256')
return token
```
### 連接 MongoDB 並驗證身分
```python
from fastapi import APIRouter, Depends, HTTPException
from fastapi.security import HTTPBasic, HTTPBasicCredentials
import pymongo
router = APIRouter()
security = HTTPBasic()
@router.post('/authenticate')
async def authenticate (credentials: HTTPBasicCredentials = Depends(security)):
client = pymongo.MongoClient(['localhost:27017'])
DATABASE = client['Fall_Detection']
result = DATABASE['user'].find_one({'username' : credentials.username})
if not result or result['password'] != credentials.password:
raise HTTPException(status_code=401, detail='Incorrect username or password')
token = generate_token(result)
return {'access_token' : token}
```
## 獲取用戶相關資訊
### JWT token 解密
```python
def get_token (auth_header: str = Depends(oauth2_scheme)):
token = auth_header
try:
payload = decode(token, SECRET_KEY, algorithms=['HS256'])
return payload
except PyJWTError as error:
raise HTTPException(status_code=401, detail=str(error))
```
### 回傳用戶資訊
```python
@router.get('/protected')
async def read_protected (token_payload: dict = Depends(get_token)):
return token_payload
```
## API 測試
測試網址:[https://reqbin.com](https://reqbin.com)
**驗證成功**

**驗證失敗**

**獲取成功**

**獲取失敗**

## 應用
### 使用 fetch 進行 POST 請求
發送帳號密碼驗證身分。
```typescript
const navigate = useNavigate();
const handleSubmit = async (event: FormEvent<HTMLFormElement>) => {
event.preventDefault();
const userData = new FormData(event.currentTarget);
const username = userData.get('username');
const password = userData.get('password');
const url = 'http://localhost:8000/api/authenticate';
const requestOptions = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Basic ${window.btoa(`${username}:${password}`)}`
},
body: JSON.stringify({ })
};
const handleResponse = async (response: Response) => {
const json = await response.json();
return (response.ok) ? json : Promise.reject(json);
}
await fetch(url, requestOptions)
.then(handleResponse)
.then((data) => {
toast.success('登入成功');
localStorage.setItem('access_token', data.access_token);
navigate('/');
})
.catch(() => toast.error('帳號或密碼錯誤'));
};
```
### 使用 fetch 進行 GET 請求
發送 token 取得用戶資料。
```typescript
const handleResponse = async (response: Response) => {
const json = await response.json();
return (response.ok) ? json : Promise.reject(json);
}
const token = localStorage.getItem('access_token');
const url = 'http://localhost:8000/api/protected';
const requestOptions = {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
}
};
fetch(url, requestOptions)
.then(handleResponse)
.then((data) => {
handleSetUser({
id: data.id,
role: data.role,
name: data.name,
username: data.username,
avatar: data.avatar,
});
});
```
