Last active
August 5, 2024 16:45
-
-
Save prestancedesign/e0da3f57d8a07855c2d9fcb26198f0b4 to your computer and use it in GitHub Desktop.
Ring session authentication with Reitit
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns authexample.web | |
(:gen-class) | |
(:require [buddy.auth :refer [authenticated? throw-unauthorized]] | |
[buddy.auth.backends.session :refer [session-backend]] | |
[buddy.auth.middleware :refer [wrap-authentication wrap-authorization]] | |
[clojure.java.io :as io] | |
[compojure.response :refer [render]] | |
[reitit.ring :as ring] | |
[ring.adapter.jetty :as jetty] | |
[ring.middleware.params :refer [wrap-params]] | |
[ring.middleware.session :refer [wrap-session]] | |
[ring.util.response :refer [redirect]])) | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
;; Controllers ;; | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
;; Home page controller (ring handler) | |
;; If incoming user is not authenticated it raises a | |
;; not authenticated exception, else it simply shows a | |
;; hello world message. | |
(defn home | |
[request] | |
(if-not (authenticated? request) | |
(throw-unauthorized) | |
(let [content (slurp (io/resource "index.html"))] | |
(render content request)))) | |
;; Login page controller | |
;; It returns a login page on get requests. | |
(defn login | |
[request] | |
(let [content (slurp (io/resource "login.html"))] | |
(render content request))) | |
;; Logout handler | |
;; Responsible for clearing the session. | |
(defn logout | |
[_] | |
(-> (redirect "/login") | |
(assoc :session {}))) | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
;; Authentication ;; | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
(def authdata | |
"Global var that stores valid users with their | |
respective passwords." | |
{:admin "secret" | |
:test "secret"}) | |
;; Authentication Handler | |
;; Used to respond to POST requests to /login. | |
(defn login-authenticate | |
"Check request username and password against authdata | |
username and passwords. | |
On successful authentication, set appropriate user | |
into the session and redirect to the value of | |
(:next (:query-params request)). On failed | |
authentication, renders the login page." | |
[request] | |
(let [username (get-in request [:form-params "username"]) | |
password (get-in request [:form-params "password"]) | |
session (:session request) | |
found-password (get authdata (keyword username))] | |
(if (and found-password (= found-password password)) | |
(let [next-url (get-in request [:query-params "next"] "/") | |
updated-session (assoc session :identity (keyword username))] | |
(-> (redirect next-url) | |
(assoc :session updated-session))) | |
(let [content (slurp (io/resource "login.html"))] | |
(render content request))))) | |
;; User defined unauthorized handler | |
;; | |
;; This function is responsible for handling | |
;; unauthorized requests (when unauthorized exception | |
;; is raised by some handler) | |
(defn unauthorized-handler | |
[request metadata] | |
(cond | |
;; If request is authenticated, raise 403 instead | |
;; of 401 (because user is authenticated but permission | |
;; denied is raised). | |
(authenticated? request) | |
(-> (render (slurp (io/resource "error.html")) request) | |
(assoc :status 403)) | |
;; In other cases, redirect the user to login page. | |
:else | |
(let [current-url (:uri request)] | |
(redirect (format "/login?next=%s" current-url))))) | |
;; Create an instance of auth backend. | |
(def auth-backend | |
(session-backend {:unauthorized-handler unauthorized-handler})) | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
;; Routes and Middlewares ;; | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
(def app | |
(ring/ring-handler | |
(ring/router | |
[["/" home] | |
["/login" {:get login | |
:post login-authenticate}] | |
["/logout" logout]] | |
{:data | |
{:middleware [[wrap-authorization auth-backend] | |
[wrap-authentication auth-backend] | |
wrap-params]}}) | |
(ring/create-default-handler) | |
{:middleware [wrap-session]})) | |
(defn -main [] | |
(jetty/run-jetty #'app {:port 3000 | |
:join? false})) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment