docs: Simplify SQL for user management how-tos
All those DROP IF EXISTS and CREATE IF NOT EXISTS etc. just give a lot more text to read and understand. If in fact a user creates the same thing twice, they should be able to understand the error message from postgres.
This commit is contained in:
committed by
Wolfgang Walther
parent
9b1ff2235a
commit
95b8751496
@@ -31,7 +31,7 @@ As in :ref:`sql_user_management`, we create a :code:`basic_auth` schema:
|
|||||||
-- We put things inside the basic_auth schema to hide
|
-- We put things inside the basic_auth schema to hide
|
||||||
-- them from public view. Certain public procs/views will
|
-- them from public view. Certain public procs/views will
|
||||||
-- refer to helpers and tables inside.
|
-- refer to helpers and tables inside.
|
||||||
CREATE SCHEMA IF NOT EXISTS basic_auth;
|
CREATE SCHEMA basic_auth;
|
||||||
|
|
||||||
|
|
||||||
As in :ref:`sql_user_management`, we create the :code:`pgcrypto` and :code:`pgjwt` extensions. Here we prefer to put the extensions in its own schemas:
|
As in :ref:`sql_user_management`, we create the :code:`pgcrypto` and :code:`pgjwt` extensions. Here we prefer to put the extensions in its own schemas:
|
||||||
@@ -40,7 +40,7 @@ As in :ref:`sql_user_management`, we create the :code:`pgcrypto` and :code:`pgjw
|
|||||||
|
|
||||||
CREATE SCHEMA ext_pgcrypto;
|
CREATE SCHEMA ext_pgcrypto;
|
||||||
ALTER SCHEMA ext_pgcrypto OWNER TO postgres;
|
ALTER SCHEMA ext_pgcrypto OWNER TO postgres;
|
||||||
CREATE EXTENSION IF NOT EXISTS pgcrypto WITH SCHEMA ext_pgcrypto;
|
CREATE EXTENSION pgcrypto WITH SCHEMA ext_pgcrypto;
|
||||||
|
|
||||||
|
|
||||||
Concerning the `pgjwt extension <https://github.com/michelp/pgjwt>`_, please cf. to :ref:`client_auth`.
|
Concerning the `pgjwt extension <https://github.com/michelp/pgjwt>`_, please cf. to :ref:`client_auth`.
|
||||||
@@ -49,7 +49,7 @@ Concerning the `pgjwt extension <https://github.com/michelp/pgjwt>`_, please cf.
|
|||||||
|
|
||||||
CREATE SCHEMA ext_pgjwt;
|
CREATE SCHEMA ext_pgjwt;
|
||||||
ALTER SCHEMA ext_pgjwt OWNER TO postgres;
|
ALTER SCHEMA ext_pgjwt OWNER TO postgres;
|
||||||
CREATE EXTENSION IF NOT EXISTS pgjwt WITH SCHEMA ext_pgjwt;
|
CREATE EXTENSION pgjwt WITH SCHEMA ext_pgjwt;
|
||||||
|
|
||||||
|
|
||||||
In order to be able to work with postgres' SCRAM-SHA-256 password hashes, we also need the PBKDF2 key derivation function. Luckily there is `a PL/pgSQL implementation on stackoverflow <https://stackoverflow.com/a/72805848>`_:
|
In order to be able to work with postgres' SCRAM-SHA-256 password hashes, we also need the PBKDF2 key derivation function. Luckily there is `a PL/pgSQL implementation on stackoverflow <https://stackoverflow.com/a/72805848>`_:
|
||||||
@@ -117,7 +117,7 @@ In order to be able to work with postgres' SCRAM-SHA-256 password hashes, we als
|
|||||||
ALTER FUNCTION basic_auth.pbkdf2(salt bytea, pw text, count integer, desired_length integer, algorithm text) OWNER TO postgres;
|
ALTER FUNCTION basic_auth.pbkdf2(salt bytea, pw text, count integer, desired_length integer, algorithm text) OWNER TO postgres;
|
||||||
|
|
||||||
|
|
||||||
Analogous to :ref:`sql_user_management` creates the function :code:`basic_auth.user_role`, we create a helper function to check the user's password, here with another name and signature (since we want the username, not an email address).
|
Analogous to how :ref:`sql_user_management` creates the function :code:`basic_auth.user_role`, we create a helper function to check the user's password, here with another name and signature (since we want the username, not an email address).
|
||||||
But contrary to :ref:`sql_user_management`, this function does not use a dedicated :code:`users` table with passwords, but instead utilizes the built-in table `pg_catalog.pg_authid <https://www.postgresql.org/docs/current/catalog-pg-authid.html>`_:
|
But contrary to :ref:`sql_user_management`, this function does not use a dedicated :code:`users` table with passwords, but instead utilizes the built-in table `pg_catalog.pg_authid <https://www.postgresql.org/docs/current/catalog-pg-authid.html>`_:
|
||||||
|
|
||||||
.. code-block:: postgres
|
.. code-block:: postgres
|
||||||
|
|||||||
@@ -17,9 +17,8 @@ First we'll need a table to keep track of our users:
|
|||||||
-- We put things inside the basic_auth schema to hide
|
-- We put things inside the basic_auth schema to hide
|
||||||
-- them from public view. Certain public procs/views will
|
-- them from public view. Certain public procs/views will
|
||||||
-- refer to helpers and tables inside.
|
-- refer to helpers and tables inside.
|
||||||
create schema if not exists basic_auth;
|
|
||||||
|
|
||||||
create table if not exists
|
create table
|
||||||
basic_auth.users (
|
basic_auth.users (
|
||||||
email text primary key check ( email ~* '^.+@.+\..+$' ),
|
email text primary key check ( email ~* '^.+@.+\..+$' ),
|
||||||
pass text not null check (length(pass) < 512),
|
pass text not null check (length(pass) < 512),
|
||||||
@@ -30,7 +29,7 @@ We would like the role to be a foreign key to actual database roles, however Pos
|
|||||||
|
|
||||||
.. code-block:: postgres
|
.. code-block:: postgres
|
||||||
|
|
||||||
create or replace function
|
create function
|
||||||
basic_auth.check_role_exists() returns trigger as $$
|
basic_auth.check_role_exists() returns trigger as $$
|
||||||
begin
|
begin
|
||||||
if not exists (select 1 from pg_roles as r where r.rolname = new.role) then
|
if not exists (select 1 from pg_roles as r where r.rolname = new.role) then
|
||||||
@@ -42,7 +41,6 @@ We would like the role to be a foreign key to actual database roles, however Pos
|
|||||||
end
|
end
|
||||||
$$ language plpgsql;
|
$$ language plpgsql;
|
||||||
|
|
||||||
drop trigger if exists ensure_user_role_exists on basic_auth.users;
|
|
||||||
create constraint trigger ensure_user_role_exists
|
create constraint trigger ensure_user_role_exists
|
||||||
after insert or update on basic_auth.users
|
after insert or update on basic_auth.users
|
||||||
for each row
|
for each row
|
||||||
@@ -52,9 +50,9 @@ Next we'll use the pgcrypto extension and a trigger to keep passwords safe in th
|
|||||||
|
|
||||||
.. code-block:: postgres
|
.. code-block:: postgres
|
||||||
|
|
||||||
create extension if not exists pgcrypto;
|
create extension pgcrypto;
|
||||||
|
|
||||||
create or replace function
|
create function
|
||||||
basic_auth.encrypt_pass() returns trigger as $$
|
basic_auth.encrypt_pass() returns trigger as $$
|
||||||
begin
|
begin
|
||||||
if tg_op = 'INSERT' or new.pass <> old.pass then
|
if tg_op = 'INSERT' or new.pass <> old.pass then
|
||||||
@@ -64,7 +62,6 @@ Next we'll use the pgcrypto extension and a trigger to keep passwords safe in th
|
|||||||
end
|
end
|
||||||
$$ language plpgsql;
|
$$ language plpgsql;
|
||||||
|
|
||||||
drop trigger if exists encrypt_pass on basic_auth.users;
|
|
||||||
create trigger encrypt_pass
|
create trigger encrypt_pass
|
||||||
before insert or update on basic_auth.users
|
before insert or update on basic_auth.users
|
||||||
for each row
|
for each row
|
||||||
@@ -74,7 +71,7 @@ With the table in place we can make a helper to check a password against the enc
|
|||||||
|
|
||||||
.. code-block:: postgres
|
.. code-block:: postgres
|
||||||
|
|
||||||
create or replace function
|
create function
|
||||||
basic_auth.user_role(email text, pass text) returns name
|
basic_auth.user_role(email text, pass text) returns name
|
||||||
language plpgsql
|
language plpgsql
|
||||||
as $$
|
as $$
|
||||||
@@ -158,7 +155,7 @@ As described in `JWT from SQL`_, we'll create a JWT inside our login function. N
|
|||||||
.. code-block:: postgres
|
.. code-block:: postgres
|
||||||
|
|
||||||
-- login should be on your exposed schema
|
-- login should be on your exposed schema
|
||||||
create or replace function
|
create function
|
||||||
login(email text, pass text, out token text) as $$
|
login(email text, pass text, out token text) as $$
|
||||||
declare
|
declare
|
||||||
_role name;
|
_role name;
|
||||||
|
|||||||
Reference in New Issue
Block a user