Projekt

Obecné

Profil

Stáhnout (7.14 KB) Statistiky
| Větev: | Tag: | Revize:
1
from fastapi import Depends, APIRouter, Form
2
from fastapi import Request
3
from fastapi.responses import HTMLResponse, RedirectResponse
4
from fastapi.templating import Jinja2Templates
5
from fastapi_jwt_auth import AuthJWT
6
from sqlalchemy.orm import Session
7
from sql_app import crud
8
from passlib.context import CryptContext
9
from pydantic import BaseModel
10
from ..database import SessionLocal, engine
11

    
12
# Path to html templates used in this file
13
templates = Jinja2Templates(directory="templates/auth")
14

    
15
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
16

    
17
# prefix used for all endpoints in this file
18
auth = APIRouter(prefix="")
19

    
20

    
21
# Dependency
22
def get_db():
23
    db = SessionLocal()
24
    try:
25
        yield db
26
    finally:
27
        db.close()
28

    
29

    
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

    
43
# admin username and password
44
fake_users_db = {
45
    "admin": {
46
        "username": "admin",
47
        "password": "admin"
48
    }
49
}
50

    
51

    
52
def verify_password(plain_password, hashed_password):
53
    """
54
    Verifies plain text password with hashed password
55
    """
56
    return pwd_context.verify(plain_password, hashed_password)
57

    
58

    
59
def get_hash_password(password):
60
    """
61
    Returns hashed password
62
    """
63
    return pwd_context.hash(password)
64

    
65

    
66
def auth_user(db, username: str, password: str):
67
    """
68
    Determines if given password belongs to user with given username
69
    """
70
    user = crud.find_user(db, username)
71
    if not user:
72
        return None
73
    if not verify_password(password, user.password):
74
        return None
75
    return user
76

    
77

    
78
@auth.get("/signup", response_class=HTMLResponse)
79
async def signup_get(request: Request):
80
    """
81
    return html template for signup
82
    """
83
    return templates.TemplateResponse("signup.html", {"request": request})
84

    
85

    
86
@auth.post("/signup", response_class=HTMLResponse)
87
async def signup(username: str = Form(...), password: str = Form(...), db: Session = Depends(get_db)):
88
    """
89
    Endpoint called form signup template. Creates new user with role guest that can be changed by admin user
90
    """
91
    users = crud.get_users(db, 0, 100)
92
    users_names = []
93
    for u in users:
94
        users_names.append(u.username)
95
    if username not in users_names:
96
        new_user = crud.create_user(db, username, get_hash_password(password), "guest")
97
        if new_user is None:
98
            print("something went wrong")
99
        return """
100
            <html>
101
                <head>
102
                    <title>Signup</title>
103
                </head>
104
                <body>
105
                    <h1>New user created. You can go back to previous page.</h1>
106
                    <form action="/logs-web" method="get">
107
                        <input type="submit" value="Home Page" />
108
                    </form>
109
                </body>
110
            </html>
111
            """
112
    else:
113
        return """
114
                    <html>
115
                        <head>
116
                            <title>Signup</title>
117
                        </head>
118
                        <body>
119
                            <h1>Username taken. Try to choose different username.</h1>
120
                            <form action="/logs-web" method="get">
121
                                <input type="submit" value="Home Page" />
122
                            </form>
123
                        </body>
124
                    </html>
125
                    """
126

    
127
@auth.get("/login", response_class=HTMLResponse)
128
async def login_get(request: Request):
129
    """
130
    return html template for login
131
    """
132
    return templates.TemplateResponse("login.html", {"request": request})
133

    
134

    
135
@auth.post("/login", response_class=HTMLResponse)
136
async def login(username: str = Form(...), password: str = Form(...), db: Session = Depends(get_db),
137
                Authorize: AuthJWT = Depends()):
138
    """
139
    Endpoint called from login template. Checks if given username and password aligns with admin
140
    username and password and returns token for browser according to given username and password
141
    """
142
    user = auth_user(db, username, password)
143
    if user != None:
144
        if user.role == "admin":
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
            access_token = Authorize.create_access_token(subject="guest", expires_time=False)
149
            refresh_token = Authorize.create_refresh_token(subject="guest", expires_time=False)
150
    else:
151
        usr = fake_users_db.get(username)
152
        if usr is not None and (usr["username"] == username and usr["password"] == password):
153
            access_token = Authorize.create_access_token(subject="admin", expires_time=False)
154
            refresh_token = Authorize.create_refresh_token(subject="admin", expires_time=False)
155
        else:
156
            return """
157
                <html>
158
                    <head>
159
                        <title>Login</title>
160
                    </head>
161
                    <body>
162
                        <h1>Wrong Username or Password</h1>
163
                        <form action="/login" method="get">
164
                            <input type="submit" value="Log again" />
165
                        </form>
166
                        <form action="/login" method="get">
167
                            <input type="submit" value="Home Page" />
168
                        </form>
169
                    </body>
170
                </html>
171
                """
172

    
173
    # Set the JWT cookies in the response
174
    Authorize.set_access_cookies(access_token)
175
    Authorize.set_refresh_cookies(refresh_token)
176
    return """
177
    <html>
178
        <head>
179
            <title>Login</title>
180
        </head>
181
        <body>
182
            <h1>Now you are logged in, you can continue to previous page.</h1>
183
            <form action="/logs-web" method="get">
184
                <input type="submit" value="Home Page" />
185
            </form>
186
        </body>
187
    </html>
188
    """
189

    
190

    
191
@auth.post('/refresh')
192
def refresh(Authorize: AuthJWT = Depends()):
193
    """
194
    endpoint for refreshing browser token. Not used at the moment since lifetime of given tokens are
195
    unlimited.
196
    """
197
    Authorize.jwt_refresh_token_required()
198
    current_user = Authorize.get_jwt_subject()
199
    new_access_token = Authorize.create_access_token(subject=current_user)
200
    # Set the JWT cookies in the response
201
    Authorize.set_access_cookies(new_access_token)
202
    return {"msg": "The token has been refresh"}
203

    
204

    
205
@auth.get('/logout', response_class=HTMLResponse)
206
def logout(Authorize: AuthJWT = Depends()):
207
    """
208
    Endpoint for deleting cookie token with acces role.
209
    """
210
    Authorize.jwt_optional()
211

    
212
    Authorize.unset_jwt_cookies()
213
    return """
214
        <html>
215
            <head>
216
                <title>Logout</title>
217
            </head>
218
            <body>
219
                <h1>Logged Out</h1>
220
                <form action="/logs-web" method="get">
221
                    <input type="submit" value="Back" />
222
                </form>
223
            </body>
224
        </html>
225
        """
(2-2/16)