feat: use requests with auth header for home

This commit is contained in:
swve 2023-05-22 16:51:51 +00:00
parent 3457b57c58
commit 9f28dfe7e8
7 changed files with 83 additions and 40 deletions

View file

@ -1,17 +1,16 @@
export const dynamic = 'force-dynamic';
import { Metadata, ResolvingMetadata } from 'next';
import { Menu } from "@components/UI/Elements/Menu";
import { getBackendUrl, getUriWithOrg } from "@services/config/config";
import { getOrgCourses } from "@services/courses/courses";
import { getCourse, getOrgCourses, getOrgCoursesWithAuthHeader } from "@services/courses/courses";
import CoursesLogo from "public/svg/courses.svg";
import CollectionsLogo from "public/svg/collections.svg";
import Link from "next/link";
import Image from "next/image";
import { log } from "console";
import AuthProvider from "@components/Security/AuthProvider";
import { getOrgCollections } from "@services/courses/collections";
import { getOrgCollections, getOrgCollectionsWithAuthHeader } from "@services/courses/collections";
import { getOrganizationContextInfo } from '@services/organizations/orgs';
import { cookies } from 'next/headers';
type MetadataProps = {
params: { orgslug: string };
searchParams: { [key: string]: string | string[] | undefined };
@ -21,6 +20,7 @@ export async function generateMetadata(
{ params }: MetadataProps,
): Promise<Metadata> {
// Get Org context information
const org = await getOrganizationContextInfo(params.orgslug, { revalidate: 1800, tags: ['organizations'] });
return {
@ -31,8 +31,12 @@ export async function generateMetadata(
const OrgHomePage = async (params: any) => {
const orgslug = params.params.orgslug;
const courses = await getOrgCourses(orgslug, { revalidate: 360 , tags: ['courses'] });
const collections = await getOrgCollections();
const cookieStore = cookies();
const access_token_cookie: any = cookieStore.get('access_token_cookie');
const courses = await getOrgCoursesWithAuthHeader(orgslug, { revalidate: 360, tags: ['courses'] }, access_token_cookie.value);
const collections = await getOrgCollectionsWithAuthHeader(access_token_cookie.value);
// function to remove "course_" from the course_id
function removeCoursePrefix(course_id: string) {

View file

@ -12,8 +12,7 @@ export async function loginAndGetToken(username: string, password: string): Prom
// Request Config
// get origin
const origin = window.location.origin;
const HeadersConfig = new Headers({ "Content-Type": "application/x-www-form-urlencoded" , Origin: origin });
const HeadersConfig = new Headers({ "Content-Type": "application/x-www-form-urlencoded" });
const urlencoded = new URLSearchParams({ username: username, password: password });
const requestOptions: any = {

View file

@ -1,5 +1,5 @@
import { getAPIUrl } from "../config/config";
import { RequestBody, errorHandling } from "@services/utils/ts/requests";
import { RequestBody, RequestBodyWithAuthHeader, errorHandling } from "@services/utils/ts/requests";
/*
This file includes only POST, PUT, DELETE requests
@ -19,7 +19,7 @@ export async function createCollection(collection: any) {
return res;
}
// Get collections
// Get collections
// TODO : add per org filter
export async function getOrgCollections() {
const result: any = await fetch(`${getAPIUrl()}collections/page/1/limit/10`, { next: { revalidate: 10 } });
@ -27,3 +27,8 @@ export async function getOrgCollections() {
return res;
}
export async function getOrgCollectionsWithAuthHeader(access_token: string) {
const result: any = await fetch(`${getAPIUrl()}collections/page/1/limit/10`, RequestBodyWithAuthHeader("GET", null, { revalidate: 10 }, access_token));
const res = await errorHandling(result);
return res;
}

View file

@ -1,5 +1,5 @@
import { getAPIUrl } from "@services/config/config";
import { RequestBody, RequestBodyForm, errorHandling } from "@services/utils/ts/requests";
import { RequestBody, RequestBodyForm, RequestBodyWithAuthHeader, errorHandling } from "@services/utils/ts/requests";
/*
This file includes only POST, PUT, DELETE requests
@ -9,10 +9,17 @@ import { RequestBody, RequestBodyForm, errorHandling } from "@services/utils/ts/
export async function getOrgCourses(org_id: number, next: any) {
const result: any = await fetch(`${getAPIUrl()}courses/org_slug/${org_id}/page/1/limit/10`, RequestBody("GET", null, next));
const res = await errorHandling(result);
return res;
}
export async function getOrgCoursesWithAuthHeader(org_id: number, next: any, access_token: string) {
const result: any = await fetch(`${getAPIUrl()}courses/org_slug/${org_id}/page/1/limit/10`, RequestBodyWithAuthHeader("GET", null, next, access_token));
const res = await errorHandling(result);
return res;
}
export async function getCourse(course_id: string, next: any) {
const result: any = await fetch(`${getAPIUrl()}courses/${course_id}`, RequestBody("GET", null, next));
const res = await errorHandling(result);

View file

@ -18,6 +18,20 @@ export const RequestBody = (method: string, data: any, next: any) => {
return options;
};
export const RequestBodyWithAuthHeader = (method: string, data: any, next: any, token: string) => {
let HeadersConfig = new Headers({ Authorization: `Bearer ${token}` });
let options: any = {
method: method,
headers: HeadersConfig,
redirect: "follow",
credentials: "include",
body: data,
// Next.js
next: next,
};
return options;
};
export const RequestBodyForm = (method: string, data: any, next: any) => {
let HeadersConfig = new Headers({});
let options: any = {

View file

@ -1,13 +1,14 @@
from urllib.request import Request
from fastapi import Depends, APIRouter, HTTPException, status, Request
from fastapi.security import OAuth2PasswordRequestForm
from fastapi import Depends, APIRouter, HTTPException, Response, status, Request
from fastapi.security import OAuth2PasswordRequestForm
from src.security.auth import *
from src.services.users.users import *
router = APIRouter()
@router.post('/refresh')
@router.post("/refresh")
def refresh(Authorize: AuthJWT = Depends()):
"""
The jwt_refresh_token_required() function insures a valid refresh
@ -18,11 +19,17 @@ def refresh(Authorize: AuthJWT = Depends()):
Authorize.jwt_refresh_token_required()
current_user = Authorize.get_jwt_subject()
new_access_token = Authorize.create_access_token(subject=current_user) # type: ignore
new_access_token = Authorize.create_access_token(subject=current_user) # type: ignore
return {"access_token": new_access_token}
@router.post('/login')
async def login(request: Request,Authorize: AuthJWT = Depends(), form_data: OAuth2PasswordRequestForm = Depends()):
@router.post("/login")
async def login(
request: Request,
response: Response,
Authorize: AuthJWT = Depends(),
form_data: OAuth2PasswordRequestForm = Depends(),
):
user = await authenticate_user(request, form_data.username, form_data.password)
if not user:
raise HTTPException(
@ -34,10 +41,17 @@ async def login(request: Request,Authorize: AuthJWT = Depends(), form_data: OAut
access_token = Authorize.create_access_token(subject=form_data.username)
refresh_token = Authorize.create_refresh_token(subject=form_data.username)
Authorize.set_refresh_cookies(refresh_token)
Authorize.set_access_cookies(access_token)
return {"access_token": access_token , "refresh_token": refresh_token}
# set cookies using fastapi
response.set_cookie(key="access_token_cookie", value=access_token , httponly=False)
@router.delete('/logout')
result = {
"user": user,
"tokens": {"access_token": access_token, "refresh_token": refresh_token},
}
return result
@router.delete("/logout")
def logout(Authorize: AuthJWT = Depends()):
"""
Because the JWT are stored in an httponly cookie now, we cannot
@ -47,4 +61,4 @@ def logout(Authorize: AuthJWT = Depends()):
Authorize.jwt_required()
Authorize.unset_jwt_cookies()
return {"msg":"Successfully logout"}
return {"msg": "Successfully logout"}

View file

@ -10,26 +10,26 @@ from fastapi_jwt_auth import AuthJWT
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/auth/login")
#### JWT Auth ####################################################
class Settings(BaseModel):
authjwt_secret_key: str = "secret"
authjwt_token_location = {"cookies"}
authjwt_token_location = {"cookies", "headers"}
authjwt_cookie_csrf_protect = False
authjwt_access_token_expires = False # (pre-alpha only) # TODO: set to 1 hour
authjwt_cookie_samesite = "none"
authjwt_access_token_expires = False # (pre-alpha only) # TODO: set to 1 hour
authjwt_cookie_samesite = "lax"
authjwt_cookie_secure = True
@AuthJWT.load_config # type: ignore
authjwt_cookie_domain = ".localhost"
@AuthJWT.load_config # type: ignore
def get_config():
return Settings()
#### JWT Auth ####################################################
#### Classes ####################################################
@ -41,10 +41,11 @@ class Token(BaseModel):
class TokenData(BaseModel):
username: str | None = None
#### Classes ####################################################
async def authenticate_user(request: Request,email: str, password: str):
async def authenticate_user(request: Request, email: str, password: str):
user = await security_get_user(request, email)
if not user:
return False
@ -64,29 +65,28 @@ def create_access_token(data: dict, expires_delta: timedelta | None = None):
return encoded_jwt
async def get_current_user(request: Request, Authorize: AuthJWT = Depends()):
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"},
)
try:
Authorize.jwt_optional()
username = Authorize.get_jwt_subject() or None
token_data = TokenData(username=username) # type: ignore
except JWTError:
raise credentials_exception
if username:
user = await security_get_user(request, email=token_data.username) # type: ignore # treated as an email
if username:
user = await security_get_user(request, email=token_data.username) # type: ignore # treated as an email
if user is None:
raise credentials_exception
return PublicUser(**user.dict())
else:
return AnonymousUser()
async def non_public_endpoint(current_user: PublicUser ):
async def non_public_endpoint(current_user: PublicUser):
if isinstance(current_user, AnonymousUser):
raise HTTPException(status_code=401, detail="Not authenticated")
raise HTTPException(status_code=401, detail="Not authenticated")