Skip to content

Instantly share code, notes, and snippets.

@tabdon
Created January 18, 2024 08:36
Show Gist options
  • Save tabdon/d568ae78f4751c082deca08e9af5862a to your computer and use it in GitHub Desktop.
Save tabdon/d568ae78f4751c082deca08e9af5862a to your computer and use it in GitHub Desktop.
# Django-ninja APIs (Python)
from ninja import Router, Schema
from django.http import JsonResponse
from django.contrib.auth import authenticate, login
from django.views.decorators.csrf import ensure_csrf_cookie
from django.contrib.auth.models import User
from ninja.errors import HttpError
router = Router()
_TGS = ['User API']
class UserIn(Schema):
email: str
password: str
class UserOut(Schema):
id: int
email: str
class LoginIn(Schema):
email: str
password: str
@router.get("/me", tags=_TGS, response=UserOut)
def get_me(request):
if request.user:
return request.user
else:
raise HttpError(401, "Need to login.")
@router.post("/login", tags=_TGS, response=UserOut, auth=None)
def login_user(request, payload: LoginIn):
user = User(**payload.dict())
user = authenticate(request, email=user.email, password=user.password)
if user is not None:
login(request, user)
print("login good")
return user
else:
print("login bad")
return JsonResponse({"error": "email or password is incorrect"})
@router.get('/set-cookie', tags=_TGS, auth=None)
@ensure_csrf_cookie
def login_set_cookie(request):
"""
`login_view` requires that a csrf cookie be set.
`getCsrfToken` in `auth.js` uses this cookie to
make a request to `login_view`
"""
return JsonResponse({"details": "CSRF cookie set"})
# React Component for Login
import { useState } from "react";
import { useNavigate } from "react-router-dom";
import { getCSRFToken } from "../../utils/csrf";
const Login = () => {
const navigate = useNavigate();
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState("");
const handleLogin = async () => {
try {
const response = await fetch("/api/user/login", {
method: "POST",
headers: {
"Content-Type": "application/json",
'X-CSRFToken': getCSRFToken(),
},
body: JSON.stringify({ email, password }),
});
if (response.ok) {
const data = await response.json();
setError('');
navigate('/app/dash/');
console.log(data);
} else {
setError("Failed to login. Please try again.");
}
} catch (err) {
setError("Failed to fetch. Please try again.");
console.error(err);
}
};
return (
<div className="flex justify-center items-center h-screen bg-gray-100">
<div className="bg-white p-8 rounded-lg shadow-md w-96">
{error && <div className="text-red-500 mb-4">{error}</div>}
<div className="mb-4">
<label className="block text-gray-700 text-sm font-bold mb-2" htmlFor="username">
Username
</label>
<input
id="email"
type="text"
placeholder="Username"
value={email}
onChange={(e) => setEmail(e.target.value)}
className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
/>
</div>
<div className="mb-4">
<label className="block text-gray-700 text-sm font-bold mb-2" htmlFor="password">
Password
</label>
<input
id="password"
type="password"
placeholder="Password"
value={password}
onChange={(e) => setPassword(e.target.value)}
className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
/>
</div>
<div className="flex items-center justify-between">
<button
onClick={handleLogin}
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline"
>
Login
</button>
</div>
</div>
</div>
);
};
export default Login;
# CSRF.js utility
export const getCSRFToken = () => {
const cookies = document.cookie.split("; ");
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].split("=");
if (cookie[0] === "csrftoken") {
return cookie[1];
}
}
return "";
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment