mirror of
https://github.com/rzmk/learnhouse.git
synced 2025-12-19 04:19:25 +00:00
feat: use requests with auth header for home
This commit is contained in:
parent
3457b57c58
commit
9f28dfe7e8
7 changed files with 83 additions and 40 deletions
|
|
@ -1,17 +1,16 @@
|
||||||
export const dynamic = 'force-dynamic';
|
export const dynamic = 'force-dynamic';
|
||||||
import { Metadata, ResolvingMetadata } from 'next';
|
import { Metadata, ResolvingMetadata } from 'next';
|
||||||
import { Menu } from "@components/UI/Elements/Menu";
|
|
||||||
import { getBackendUrl, getUriWithOrg } from "@services/config/config";
|
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 CoursesLogo from "public/svg/courses.svg";
|
||||||
import CollectionsLogo from "public/svg/collections.svg";
|
import CollectionsLogo from "public/svg/collections.svg";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import { log } from "console";
|
import { getOrgCollections, getOrgCollectionsWithAuthHeader } from "@services/courses/collections";
|
||||||
import AuthProvider from "@components/Security/AuthProvider";
|
|
||||||
import { getOrgCollections } from "@services/courses/collections";
|
|
||||||
import { getOrganizationContextInfo } from '@services/organizations/orgs';
|
import { getOrganizationContextInfo } from '@services/organizations/orgs';
|
||||||
|
|
||||||
|
import { cookies } from 'next/headers';
|
||||||
|
|
||||||
type MetadataProps = {
|
type MetadataProps = {
|
||||||
params: { orgslug: string };
|
params: { orgslug: string };
|
||||||
searchParams: { [key: string]: string | string[] | undefined };
|
searchParams: { [key: string]: string | string[] | undefined };
|
||||||
|
|
@ -21,6 +20,7 @@ export async function generateMetadata(
|
||||||
{ params }: MetadataProps,
|
{ params }: MetadataProps,
|
||||||
): Promise<Metadata> {
|
): Promise<Metadata> {
|
||||||
|
|
||||||
|
|
||||||
// Get Org context information
|
// Get Org context information
|
||||||
const org = await getOrganizationContextInfo(params.orgslug, { revalidate: 1800, tags: ['organizations'] });
|
const org = await getOrganizationContextInfo(params.orgslug, { revalidate: 1800, tags: ['organizations'] });
|
||||||
return {
|
return {
|
||||||
|
|
@ -31,8 +31,12 @@ export async function generateMetadata(
|
||||||
|
|
||||||
const OrgHomePage = async (params: any) => {
|
const OrgHomePage = async (params: any) => {
|
||||||
const orgslug = params.params.orgslug;
|
const orgslug = params.params.orgslug;
|
||||||
const courses = await getOrgCourses(orgslug, { revalidate: 360 , tags: ['courses'] });
|
const cookieStore = cookies();
|
||||||
const collections = await getOrgCollections();
|
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 to remove "course_" from the course_id
|
||||||
function removeCoursePrefix(course_id: string) {
|
function removeCoursePrefix(course_id: string) {
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,7 @@ export async function loginAndGetToken(username: string, password: string): Prom
|
||||||
// Request Config
|
// Request Config
|
||||||
|
|
||||||
// get origin
|
// get origin
|
||||||
const origin = window.location.origin;
|
const HeadersConfig = new Headers({ "Content-Type": "application/x-www-form-urlencoded" });
|
||||||
const HeadersConfig = new Headers({ "Content-Type": "application/x-www-form-urlencoded" , Origin: origin });
|
|
||||||
const urlencoded = new URLSearchParams({ username: username, password: password });
|
const urlencoded = new URLSearchParams({ username: username, password: password });
|
||||||
|
|
||||||
const requestOptions: any = {
|
const requestOptions: any = {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { getAPIUrl } from "../config/config";
|
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
|
This file includes only POST, PUT, DELETE requests
|
||||||
|
|
@ -27,3 +27,8 @@ export async function getOrgCollections() {
|
||||||
return res;
|
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;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { getAPIUrl } from "@services/config/config";
|
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
|
This file includes only POST, PUT, DELETE requests
|
||||||
|
|
@ -13,6 +13,13 @@ export async function getOrgCourses(org_id: number, next: any) {
|
||||||
return res;
|
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) {
|
export async function getCourse(course_id: string, next: any) {
|
||||||
const result: any = await fetch(`${getAPIUrl()}courses/${course_id}`, RequestBody("GET", null, next));
|
const result: any = await fetch(`${getAPIUrl()}courses/${course_id}`, RequestBody("GET", null, next));
|
||||||
const res = await errorHandling(result);
|
const res = await errorHandling(result);
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,20 @@ export const RequestBody = (method: string, data: any, next: any) => {
|
||||||
return options;
|
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) => {
|
export const RequestBodyForm = (method: string, data: any, next: any) => {
|
||||||
let HeadersConfig = new Headers({});
|
let HeadersConfig = new Headers({});
|
||||||
let options: any = {
|
let options: any = {
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,14 @@
|
||||||
from urllib.request import Request
|
from urllib.request import Request
|
||||||
from fastapi import Depends, APIRouter, HTTPException, status, Request
|
from fastapi import Depends, APIRouter, HTTPException, Response, status, Request
|
||||||
from fastapi.security import OAuth2PasswordRequestForm
|
from fastapi.security import OAuth2PasswordRequestForm
|
||||||
from src.security.auth import *
|
from src.security.auth import *
|
||||||
from src.services.users.users import *
|
from src.services.users.users import *
|
||||||
|
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
@router.post('/refresh')
|
|
||||||
|
@router.post("/refresh")
|
||||||
def refresh(Authorize: AuthJWT = Depends()):
|
def refresh(Authorize: AuthJWT = Depends()):
|
||||||
"""
|
"""
|
||||||
The jwt_refresh_token_required() function insures a valid refresh
|
The jwt_refresh_token_required() function insures a valid refresh
|
||||||
|
|
@ -18,11 +19,17 @@ def refresh(Authorize: AuthJWT = Depends()):
|
||||||
Authorize.jwt_refresh_token_required()
|
Authorize.jwt_refresh_token_required()
|
||||||
|
|
||||||
current_user = Authorize.get_jwt_subject()
|
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}
|
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)
|
user = await authenticate_user(request, form_data.username, form_data.password)
|
||||||
if not user:
|
if not user:
|
||||||
raise HTTPException(
|
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)
|
access_token = Authorize.create_access_token(subject=form_data.username)
|
||||||
refresh_token = Authorize.create_refresh_token(subject=form_data.username)
|
refresh_token = Authorize.create_refresh_token(subject=form_data.username)
|
||||||
Authorize.set_refresh_cookies(refresh_token)
|
Authorize.set_refresh_cookies(refresh_token)
|
||||||
Authorize.set_access_cookies(access_token)
|
# set cookies using fastapi
|
||||||
return {"access_token": access_token , "refresh_token": refresh_token}
|
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()):
|
def logout(Authorize: AuthJWT = Depends()):
|
||||||
"""
|
"""
|
||||||
Because the JWT are stored in an httponly cookie now, we cannot
|
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.jwt_required()
|
||||||
|
|
||||||
Authorize.unset_jwt_cookies()
|
Authorize.unset_jwt_cookies()
|
||||||
return {"msg":"Successfully logout"}
|
return {"msg": "Successfully logout"}
|
||||||
|
|
|
||||||
|
|
@ -10,26 +10,26 @@ from fastapi_jwt_auth import AuthJWT
|
||||||
|
|
||||||
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/auth/login")
|
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/auth/login")
|
||||||
|
|
||||||
|
|
||||||
#### JWT Auth ####################################################
|
#### JWT Auth ####################################################
|
||||||
class Settings(BaseModel):
|
class Settings(BaseModel):
|
||||||
authjwt_secret_key: str = "secret"
|
authjwt_secret_key: str = "secret"
|
||||||
authjwt_token_location = {"cookies"}
|
authjwt_token_location = {"cookies", "headers"}
|
||||||
authjwt_cookie_csrf_protect = False
|
authjwt_cookie_csrf_protect = False
|
||||||
authjwt_access_token_expires = False # (pre-alpha only) # TODO: set to 1 hour
|
authjwt_access_token_expires = False # (pre-alpha only) # TODO: set to 1 hour
|
||||||
authjwt_cookie_samesite = "none"
|
authjwt_cookie_samesite = "lax"
|
||||||
authjwt_cookie_secure = True
|
authjwt_cookie_secure = True
|
||||||
|
authjwt_cookie_domain = ".localhost"
|
||||||
|
|
||||||
|
|
||||||
@AuthJWT.load_config # type: ignore
|
@AuthJWT.load_config # type: ignore
|
||||||
def get_config():
|
def get_config():
|
||||||
return Settings()
|
return Settings()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### JWT Auth ####################################################
|
#### JWT Auth ####################################################
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### Classes ####################################################
|
#### Classes ####################################################
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -41,10 +41,11 @@ class Token(BaseModel):
|
||||||
class TokenData(BaseModel):
|
class TokenData(BaseModel):
|
||||||
username: str | None = None
|
username: str | None = None
|
||||||
|
|
||||||
|
|
||||||
#### Classes ####################################################
|
#### 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)
|
user = await security_get_user(request, email)
|
||||||
if not user:
|
if not user:
|
||||||
return False
|
return False
|
||||||
|
|
@ -64,8 +65,6 @@ def create_access_token(data: dict, expires_delta: timedelta | None = None):
|
||||||
return encoded_jwt
|
return encoded_jwt
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async def get_current_user(request: Request, Authorize: AuthJWT = Depends()):
|
async def get_current_user(request: Request, Authorize: AuthJWT = Depends()):
|
||||||
credentials_exception = HTTPException(
|
credentials_exception = HTTPException(
|
||||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||||
|
|
@ -80,13 +79,14 @@ async def get_current_user(request: Request, Authorize: AuthJWT = Depends()):
|
||||||
except JWTError:
|
except JWTError:
|
||||||
raise credentials_exception
|
raise credentials_exception
|
||||||
if username:
|
if username:
|
||||||
user = await security_get_user(request, email=token_data.username) # type: ignore # treated as an email
|
user = await security_get_user(request, email=token_data.username) # type: ignore # treated as an email
|
||||||
if user is None:
|
if user is None:
|
||||||
raise credentials_exception
|
raise credentials_exception
|
||||||
return PublicUser(**user.dict())
|
return PublicUser(**user.dict())
|
||||||
else:
|
else:
|
||||||
return AnonymousUser()
|
return AnonymousUser()
|
||||||
|
|
||||||
async def non_public_endpoint(current_user: PublicUser ):
|
|
||||||
|
async def non_public_endpoint(current_user: PublicUser):
|
||||||
if isinstance(current_user, AnonymousUser):
|
if isinstance(current_user, AnonymousUser):
|
||||||
raise HTTPException(status_code=401, detail="Not authenticated")
|
raise HTTPException(status_code=401, detail="Not authenticated")
|
||||||
Loading…
Add table
Add a link
Reference in a new issue