Skip to content

Instantly share code, notes, and snippets.

@tabdon
Created January 18, 2024 08:36
Show Gist options
  • Select an option

  • Save tabdon/d568ae78f4751c082deca08e9af5862a to your computer and use it in GitHub Desktop.

Select an option

Save tabdon/d568ae78f4751c082deca08e9af5862a to your computer and use it in GitHub Desktop.

Revisions

  1. tabdon created this gist Jan 18, 2024.
    156 changes: 156 additions & 0 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,156 @@
    # 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 "";
    };