You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: examples/user-authentication/README.md
+44-16
Original file line number
Diff line number
Diff line change
@@ -1,23 +1,39 @@
1
1
# User authentication demo
2
2
3
-
This example demonstrates how to manually handle user authentication with SQLpage and PostgreSQL.
4
-
All the user and password management is done in the database, using the standard [pgcrypto](https://www.postgresql.org/docs/current/pgcrypto.html) postgresql extension.
3
+
This example demonstrates how to handle user authentication with SQLpage.
4
+
5
+
It uses a PostgreSQL database to store user information and session ids,
6
+
but the same principles can be applied to other databases.
7
+
8
+
All the user and password management is done in SQLPage,
9
+
which uses [best practices](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#maximum-password-lengths) for password storage.
5
10
6
11
This demonstrates how to implement:
7
-
-[a signup form](./sign%20up.sql)
8
-
-[a login form](./sign%20in.sql)
12
+
-[a signup form](./signup.sql)
13
+
-[a login form](./signin.sql)
9
14
-[a logout button](./logout.sql)
10
15
-[secured pages](./protected_page.sql) that can only be accessed by logged-in users
11
16
12
17
User authentication is a complex topic, and you can follow the work on implementing differenet authentication methods in [this issue](https://github.com/lovasoa/SQLpage/issues/12).
13
18
19
+
## How to run
20
+
21
+
Install [docker](https://docs.docker.com/get-docker/) and [docker-compose](https://docs.docker.com/compose/install/).
22
+
23
+
Then run the following command in this directory:
24
+
25
+
```bash
26
+
docker-compose up
27
+
```
28
+
29
+
Then open [http://localhost:8080](http://localhost:8080) in your browser.
30
+
14
31
## Caveats
15
32
16
-
In this example, we store encrypted user passwords in the database, but we let the database itself handle the encryption.
17
-
For that to be safe, you need to make sure that:
18
-
- the database is not accessible by untrusted users
19
-
- the database logs and configuration files are not accessible by untrusted users
20
-
- either your connection to the database is encrypted [(use SSL)](https://www.postgresql.org/docs/current/ssl-tcp.html) or you can trust all the machines on the network between your application and the database. Connections should be encrypted by default if you use a recent version of PostgreSQL and a popular distribution.
33
+
In this example, we handle user creation and login in SQLpage.
34
+
35
+
If you are implementing user authentication in an public application with potentially sensitive data,
36
+
you should propably read the [Authentication Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html) from OWASP.
21
37
22
38
## Screenshots
23
39
@@ -30,28 +46,40 @@ For that to be safe, you need to make sure that:
30
46
31
47
### User creation
32
48
33
-
The [signup form](./sign%20up.sql) is a simple form that is handled by [`create_user.sql`](./create_user.sql).
49
+
The [signup form](./signup.sql) is a simple form that is handled by [`create_user.sql`](./create_user.sql).
34
50
You could restrict user creation to existing administrators and create an initial administrator in a database migration.
35
51
36
52
### User login
37
53
38
-
The [login form](./sign%20in.sql) is a simple form that is handled by [`login.sql`](./login.sql).
39
-
It checks that the username exists and that the password is correct using the [pgcrypto](https://www.postgresql.org/docs/current/pgcrypto.html) extension with
54
+
The [login form](./signin.sql) is a simple form that is handled by [`login.sql`](./login.sql).
55
+
56
+
`login.sql` checks that the username exists and that the password is correct using the [authentication component](https://sql.ophir.dev/documentation.sql?component=authentication#component) extension with
40
57
41
58
```sql
42
-
SELECT*FROM users WHERE username = :username AND password = crypt(:password, password);
59
+
SELECT'authentication'AS component,
60
+
'signin.sql'AS link,
61
+
(SELECT password_hash FROM user_info WHERE username = :username) AS password_hash,
62
+
:password AS password;
43
63
```
44
64
45
65
If the login is successful, an entry is added to the [`login_session`](./sqlpage/migrations/0000_init.sql) table with a random session id.
66
+
67
+
If it is not, the authentication component will redirect the user to the login page and stop the execution of the page.
68
+
46
69
The session id is then stored in a cookie on the user's browser.
47
70
48
-
The user is then redirected to [`./check_login.sql`](./check_login.sql)that checks that the session id is valid and redirects back to the login page if it is not.
71
+
The user is then redirected to [`./protected_page.sql`](./protected_page.sql)which will check that the user is logged in.
49
72
50
73
### Protected pages
51
74
52
75
Protected pages are pages that can only be accessed by logged-in users.
53
-
There is an example in [`protected_page.sql`](./protected_page.sql) that uses a simple [postgresql stored procedure](./sqlpage/migrations/0000_init.sql)
54
-
to raise an error (and thus prevent content rendering) if the user is not logged in.
76
+
77
+
There is an example in [`protected_page.sql`](./protected_page.sql) that uses
78
+
the [`redirect`](https://sql.ophir.dev/documentation.sql?component=redirect#component)
79
+
component to redirect the user to the login page if they are not logged in.
80
+
81
+
Checking whether the user is logged in is as simple as checking that session id returned by [`sqlpage.cookie('session')`](https://sql.ophir.dev/functions.sql?function=cookie#function) exists in the [`login_session`](./sqlpage/migrations/0000_init.sql) table.
Copy file name to clipboardExpand all lines: examples/user-authentication/signup.sql
+1-1
Original file line number
Diff line number
Diff line change
@@ -4,5 +4,5 @@ SELECT 'form' AS component,
4
4
'create_user.sql'AS action;
5
5
6
6
SELECT'username'AS name;
7
-
SELECT'password'AS name, 'password'AS type;
7
+
SELECT'password'AS name, 'password'AS type, '^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$'AS pattern, 'Password must be at least 8 characters long and contain at least one letter and one number.'AS description;
8
8
SELECT'terms'AS name, 'I accept the terms and conditions'AS label, TRUE AS required, FALSE AS value, 'checkbox'AS type;
0 commit comments