1 |
2fe004b1
|
Matej Zeman
|
from fastapi import Depends, APIRouter, Form
|
2 |
|
|
from fastapi import Request
|
3 |
5dc6d077
|
Matej Zeman
|
from fastapi.responses import HTMLResponse, RedirectResponse
|
4 |
2fe004b1
|
Matej Zeman
|
from fastapi.templating import Jinja2Templates
|
5 |
|
|
from fastapi_jwt_auth import AuthJWT
|
6 |
cbd239c6
|
Matej Zeman
|
from sqlalchemy.orm import Session
|
7 |
|
|
from sql_app import crud
|
8 |
|
|
from passlib.context import CryptContext
|
9 |
2fe004b1
|
Matej Zeman
|
from pydantic import BaseModel
|
10 |
cbd239c6
|
Matej Zeman
|
from ..database import SessionLocal, engine
|
11 |
2fe004b1
|
Matej Zeman
|
|
12 |
|
|
# Path to html templates used in this file
|
13 |
|
|
templates = Jinja2Templates(directory="templates/auth")
|
14 |
|
|
|
15 |
cbd239c6
|
Matej Zeman
|
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
16 |
|
|
|
17 |
2fe004b1
|
Matej Zeman
|
# prefix used for all endpoints in this file
|
18 |
|
|
auth = APIRouter(prefix="")
|
19 |
|
|
|
20 |
|
|
|
21 |
cbd239c6
|
Matej Zeman
|
# Dependency
|
22 |
|
|
def get_db():
|
23 |
|
|
db = SessionLocal()
|
24 |
|
|
try:
|
25 |
|
|
yield db
|
26 |
|
|
finally:
|
27 |
|
|
db.close()
|
28 |
|
|
|
29 |
2fe004b1
|
Matej Zeman
|
|
30 |
|
|
class Settings(BaseModel):
|
31 |
|
|
authjwt_secret_key: str = "secret"
|
32 |
|
|
# Configure application to store and get JWT from cookies
|
33 |
|
|
authjwt_token_location: set = {"cookies"}
|
34 |
|
|
# Disable CSRF Protection for this example. default is True
|
35 |
|
|
authjwt_cookie_csrf_protect: bool = False
|
36 |
|
|
|
37 |
|
|
|
38 |
|
|
@AuthJWT.load_config
|
39 |
|
|
def get_config():
|
40 |
|
|
return Settings()
|
41 |
|
|
|
42 |
cbd239c6
|
Matej Zeman
|
|
43 |
7fe7be79
|
zemanm98@students.zcu.cz
|
# admin username and password
|
44 |
2fe004b1
|
Matej Zeman
|
fake_users_db = {
|
45 |
|
|
"admin": {
|
46 |
|
|
"username": "admin",
|
47 |
|
|
"password": "admin"
|
48 |
|
|
}
|
49 |
|
|
}
|
50 |
|
|
|
51 |
|
|
|
52 |
cbd239c6
|
Matej Zeman
|
def verify_password(plain_password, hashed_password):
|
53 |
|
|
return pwd_context.verify(plain_password, hashed_password)
|
54 |
|
|
|
55 |
|
|
|
56 |
|
|
def get_hash_password(password):
|
57 |
|
|
return pwd_context.hash(password)
|
58 |
|
|
|
59 |
|
|
|
60 |
|
|
def auth_user(db, username: str, password: str):
|
61 |
|
|
user = crud.find_user(db, username)
|
62 |
|
|
if not user:
|
63 |
|
|
return None
|
64 |
|
|
if not verify_password(password, user.password):
|
65 |
|
|
return None
|
66 |
|
|
return user
|
67 |
|
|
|
68 |
|
|
|
69 |
|
|
@auth.get("/signup", response_class=HTMLResponse)
|
70 |
|
|
async def signup_get(request: Request):
|
71 |
|
|
"""
|
72 |
|
|
return html template for signup
|
73 |
|
|
"""
|
74 |
|
|
return templates.TemplateResponse("signup.html", {"request": request})
|
75 |
|
|
|
76 |
|
|
|
77 |
|
|
@auth.post("/signup", response_class=HTMLResponse)
|
78 |
|
|
async def signup(username: str = Form(...), password: str = Form(...), db: Session = Depends(get_db)):
|
79 |
|
|
"""
|
80 |
|
|
Endpoint called form signup template. Creates new user with role guest that can be changed by admin user
|
81 |
|
|
"""
|
82 |
|
|
users = crud.get_users(db, 0, 100)
|
83 |
|
|
users_names = []
|
84 |
|
|
for u in users:
|
85 |
|
|
users_names.append(u.username)
|
86 |
|
|
if username not in users_names:
|
87 |
|
|
new_user = crud.create_user(db, username, get_hash_password(password), "guest")
|
88 |
|
|
if new_user is None:
|
89 |
|
|
print("something went wrong")
|
90 |
|
|
return """
|
91 |
|
|
<html>
|
92 |
|
|
<head>
|
93 |
|
|
<title>Signup</title>
|
94 |
|
|
</head>
|
95 |
|
|
<body>
|
96 |
2552e614
|
Matej Zeman
|
<h1>New user created. You can go back to previous page.</h1>
|
97 |
cbd239c6
|
Matej Zeman
|
<form action="/logs-web" method="get">
|
98 |
2552e614
|
Matej Zeman
|
<input type="submit" value="Home Page" />
|
99 |
cbd239c6
|
Matej Zeman
|
</form>
|
100 |
|
|
</body>
|
101 |
|
|
</html>
|
102 |
|
|
"""
|
103 |
|
|
else:
|
104 |
|
|
return """
|
105 |
|
|
<html>
|
106 |
|
|
<head>
|
107 |
|
|
<title>Signup</title>
|
108 |
|
|
</head>
|
109 |
|
|
<body>
|
110 |
2552e614
|
Matej Zeman
|
<h1>Username taken. Try to choose different username.</h1>
|
111 |
cbd239c6
|
Matej Zeman
|
<form action="/logs-web" method="get">
|
112 |
2552e614
|
Matej Zeman
|
<input type="submit" value="Home Page" />
|
113 |
cbd239c6
|
Matej Zeman
|
</form>
|
114 |
|
|
</body>
|
115 |
|
|
</html>
|
116 |
|
|
"""
|
117 |
|
|
|
118 |
2fe004b1
|
Matej Zeman
|
@auth.get("/login", response_class=HTMLResponse)
|
119 |
|
|
async def login_get(request: Request):
|
120 |
7fe7be79
|
zemanm98@students.zcu.cz
|
"""
|
121 |
|
|
return html template for login
|
122 |
|
|
"""
|
123 |
2fe004b1
|
Matej Zeman
|
return templates.TemplateResponse("login.html", {"request": request})
|
124 |
|
|
|
125 |
|
|
|
126 |
|
|
@auth.post("/login", response_class=HTMLResponse)
|
127 |
cbd239c6
|
Matej Zeman
|
async def login(username: str = Form(...), password: str = Form(...), db: Session = Depends(get_db),
|
128 |
|
|
Authorize: AuthJWT = Depends()):
|
129 |
7fe7be79
|
zemanm98@students.zcu.cz
|
"""
|
130 |
|
|
Endpoint called from login template. Checks if given username and password aligns with admin
|
131 |
|
|
username and password and returns token for browser according to given username and password
|
132 |
|
|
"""
|
133 |
cbd239c6
|
Matej Zeman
|
user = auth_user(db, username, password)
|
134 |
|
|
if user != None:
|
135 |
|
|
if user.role == "admin":
|
136 |
2fe004b1
|
Matej Zeman
|
access_token = Authorize.create_access_token(subject="admin", expires_time=False)
|
137 |
|
|
refresh_token = Authorize.create_refresh_token(subject="admin", expires_time=False)
|
138 |
|
|
else:
|
139 |
cbd239c6
|
Matej Zeman
|
access_token = Authorize.create_access_token(subject="guest", expires_time=False)
|
140 |
|
|
refresh_token = Authorize.create_refresh_token(subject="guest", expires_time=False)
|
141 |
2fe004b1
|
Matej Zeman
|
else:
|
142 |
cbd239c6
|
Matej Zeman
|
usr = fake_users_db.get(username)
|
143 |
|
|
if usr != None:
|
144 |
|
|
if usr["username"] == username and usr["password"] == password:
|
145 |
|
|
access_token = Authorize.create_access_token(subject="admin", expires_time=False)
|
146 |
|
|
refresh_token = Authorize.create_refresh_token(subject="admin", expires_time=False)
|
147 |
|
|
else:
|
148 |
|
|
return """
|
149 |
|
|
<html>
|
150 |
|
|
<head>
|
151 |
|
|
<title>Login</title>
|
152 |
|
|
</head>
|
153 |
|
|
<body>
|
154 |
|
|
<h1>Wrong Username or Password</h1>
|
155 |
|
|
<form action="/login" method="get">
|
156 |
2552e614
|
Matej Zeman
|
<input type="submit" value="Log again" />
|
157 |
|
|
</form>
|
158 |
|
|
<form action="/login" method="get">
|
159 |
|
|
<input type="submit" value="Home Page" />
|
160 |
cbd239c6
|
Matej Zeman
|
</form>
|
161 |
|
|
</body>
|
162 |
|
|
</html>
|
163 |
|
|
"""
|
164 |
2fe004b1
|
Matej Zeman
|
|
165 |
|
|
# Set the JWT cookies in the response
|
166 |
|
|
Authorize.set_access_cookies(access_token)
|
167 |
|
|
Authorize.set_refresh_cookies(refresh_token)
|
168 |
|
|
return """
|
169 |
|
|
<html>
|
170 |
|
|
<head>
|
171 |
|
|
<title>Login</title>
|
172 |
|
|
</head>
|
173 |
|
|
<body>
|
174 |
2552e614
|
Matej Zeman
|
<h1>Now you are logged in, you can continue to previous page.</h1>
|
175 |
2fe004b1
|
Matej Zeman
|
<form action="/logs-web" method="get">
|
176 |
2552e614
|
Matej Zeman
|
<input type="submit" value="Home Page" />
|
177 |
2fe004b1
|
Matej Zeman
|
</form>
|
178 |
|
|
</body>
|
179 |
|
|
</html>
|
180 |
|
|
"""
|
181 |
|
|
|
182 |
|
|
|
183 |
|
|
@auth.post('/refresh')
|
184 |
|
|
def refresh(Authorize: AuthJWT = Depends()):
|
185 |
7fe7be79
|
zemanm98@students.zcu.cz
|
"""
|
186 |
|
|
endpoint for refreshing browser token. Not used at the moment since lifetime of given tokens are
|
187 |
|
|
unlimited.
|
188 |
|
|
"""
|
189 |
2fe004b1
|
Matej Zeman
|
Authorize.jwt_refresh_token_required()
|
190 |
|
|
current_user = Authorize.get_jwt_subject()
|
191 |
|
|
new_access_token = Authorize.create_access_token(subject=current_user)
|
192 |
|
|
# Set the JWT cookies in the response
|
193 |
|
|
Authorize.set_access_cookies(new_access_token)
|
194 |
|
|
return {"msg": "The token has been refresh"}
|
195 |
|
|
|
196 |
|
|
|
197 |
|
|
@auth.get('/logout', response_class=HTMLResponse)
|
198 |
|
|
def logout(Authorize: AuthJWT = Depends()):
|
199 |
|
|
"""
|
200 |
7fe7be79
|
zemanm98@students.zcu.cz
|
Endpoint for deleting cookie token with acces role.
|
201 |
2fe004b1
|
Matej Zeman
|
"""
|
202 |
|
|
Authorize.jwt_optional()
|
203 |
|
|
|
204 |
|
|
Authorize.unset_jwt_cookies()
|
205 |
|
|
return """
|
206 |
|
|
<html>
|
207 |
|
|
<head>
|
208 |
|
|
<title>Logout</title>
|
209 |
|
|
</head>
|
210 |
|
|
<body>
|
211 |
|
|
<h1>Logged Out</h1>
|
212 |
|
|
<form action="/logs-web" method="get">
|
213 |
|
|
<input type="submit" value="Back" />
|
214 |
|
|
</form>
|
215 |
|
|
</body>
|
216 |
|
|
</html>
|
217 |
cbd239c6
|
Matej Zeman
|
"""
|