Projekt

Obecné

Profil

Stáhnout (7.15 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 != None:
153
            if usr["username"] == username and usr["password"] == password:
154
                access_token = Authorize.create_access_token(subject="admin", expires_time=False)
155
                refresh_token = Authorize.create_refresh_token(subject="admin", expires_time=False)
156
        else:
157
            return """
158
                <html>
159
                    <head>
160
                        <title>Login</title>
161
                    </head>
162
                    <body>
163
                        <h1>Wrong Username or Password</h1>
164
                        <form action="/login" method="get">
165
                            <input type="submit" value="Log again" />
166
                        </form>
167
                        <form action="/login" method="get">
168
                            <input type="submit" value="Home Page" />
169
                        </form>
170
                    </body>
171
                </html>
172
                """
173

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

    
191

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

    
205

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

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