plain.auth 0.15.0__tar.gz → 0.17.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- plain_auth-0.17.0/PKG-INFO +183 -0
- {plain_auth-0.15.0 → plain_auth-0.17.0}/plain/auth/CHANGELOG.md +22 -0
- plain_auth-0.17.0/plain/auth/README.md +171 -0
- {plain_auth-0.15.0 → plain_auth-0.17.0}/plain/auth/sessions.py +1 -3
- {plain_auth-0.15.0 → plain_auth-0.17.0}/pyproject.toml +3 -3
- {plain_auth-0.15.0 → plain_auth-0.17.0}/tests/test_views.py +1 -1
- plain_auth-0.15.0/PKG-INFO +0 -128
- plain_auth-0.15.0/plain/auth/README.md +0 -116
- {plain_auth-0.15.0 → plain_auth-0.17.0}/.gitignore +0 -0
- {plain_auth-0.15.0 → plain_auth-0.17.0}/LICENSE +0 -0
- {plain_auth-0.15.0 → plain_auth-0.17.0}/README.md +0 -0
- {plain_auth-0.15.0 → plain_auth-0.17.0}/plain/auth/__init__.py +0 -0
- {plain_auth-0.15.0 → plain_auth-0.17.0}/plain/auth/default_settings.py +0 -0
- {plain_auth-0.15.0 → plain_auth-0.17.0}/plain/auth/middleware.py +0 -0
- {plain_auth-0.15.0 → plain_auth-0.17.0}/plain/auth/test.py +0 -0
- {plain_auth-0.15.0 → plain_auth-0.17.0}/plain/auth/utils.py +0 -0
- {plain_auth-0.15.0 → plain_auth-0.17.0}/plain/auth/views.py +0 -0
- {plain_auth-0.15.0 → plain_auth-0.17.0}/tests/app/settings.py +0 -0
- {plain_auth-0.15.0 → plain_auth-0.17.0}/tests/app/urls.py +0 -0
- {plain_auth-0.15.0 → plain_auth-0.17.0}/tests/app/users/migrations/0001_initial.py +0 -0
- {plain_auth-0.15.0 → plain_auth-0.17.0}/tests/app/users/migrations/__init__.py +0 -0
- {plain_auth-0.15.0 → plain_auth-0.17.0}/tests/app/users/models.py +0 -0
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: plain.auth
|
|
3
|
+
Version: 0.17.0
|
|
4
|
+
Summary: Add users to your app and decide what they can access.
|
|
5
|
+
Author-email: Dave Gaeddert <dave.gaeddert@dropseed.dev>
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Requires-Python: >=3.13
|
|
8
|
+
Requires-Dist: plain-models<1.0.0
|
|
9
|
+
Requires-Dist: plain-sessions<1.0.0
|
|
10
|
+
Requires-Dist: plain<1.0.0
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
|
|
13
|
+
# plain.auth
|
|
14
|
+
|
|
15
|
+
**Add users to your app and decide what they can access.**
|
|
16
|
+
|
|
17
|
+
- [Overview](#overview)
|
|
18
|
+
- [Authentication setup](#authentication-setup)
|
|
19
|
+
- [Settings configuration](#settings-configuration)
|
|
20
|
+
- [Creating a user model](#creating-a-user-model)
|
|
21
|
+
- [Login views](#login-views)
|
|
22
|
+
- [Checking if a user is logged in](#checking-if-a-user-is-logged-in)
|
|
23
|
+
- [Restricting views](#restricting-views)
|
|
24
|
+
- [Installation](#installation)
|
|
25
|
+
|
|
26
|
+
## Overview
|
|
27
|
+
|
|
28
|
+
The `plain.auth` package provides user authentication and authorization for Plain applications. Here's a basic example of checking if a user is logged in:
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
# In a view
|
|
32
|
+
if request.user:
|
|
33
|
+
print(f"Hello, {request.user.email}!")
|
|
34
|
+
else:
|
|
35
|
+
print("You are not logged in.")
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
And restricting a view to logged-in users:
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
from plain.auth.views import AuthViewMixin
|
|
42
|
+
from plain.views import View
|
|
43
|
+
|
|
44
|
+
class ProfileView(AuthViewMixin, View):
|
|
45
|
+
login_required = True
|
|
46
|
+
|
|
47
|
+
def get(self):
|
|
48
|
+
return f"Welcome, {self.request.user.email}!"
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Authentication setup
|
|
52
|
+
|
|
53
|
+
### Settings configuration
|
|
54
|
+
|
|
55
|
+
Configure your authentication settings in `app/settings.py`:
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
INSTALLED_PACKAGES = [
|
|
59
|
+
# ...
|
|
60
|
+
"plain.auth",
|
|
61
|
+
"plain.sessions",
|
|
62
|
+
"plain.passwords", # Or another auth method
|
|
63
|
+
]
|
|
64
|
+
|
|
65
|
+
MIDDLEWARE = [
|
|
66
|
+
"plain.sessions.middleware.SessionMiddleware",
|
|
67
|
+
"plain.auth.middleware.AuthenticationMiddleware",
|
|
68
|
+
]
|
|
69
|
+
|
|
70
|
+
AUTH_USER_MODEL = "users.User"
|
|
71
|
+
AUTH_LOGIN_URL = "login"
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Creating a user model
|
|
75
|
+
|
|
76
|
+
Create your own user model using `plain create users` or manually:
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
# app/users/models.py
|
|
80
|
+
from plain import models
|
|
81
|
+
from plain.passwords.models import PasswordField
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class User(models.Model):
|
|
85
|
+
email = models.EmailField()
|
|
86
|
+
password = PasswordField()
|
|
87
|
+
is_admin = models.BooleanField(default=False)
|
|
88
|
+
created_at = models.DateTimeField(auto_now_add=True)
|
|
89
|
+
|
|
90
|
+
def __str__(self):
|
|
91
|
+
return self.email
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Login views
|
|
95
|
+
|
|
96
|
+
To log users in, you'll need to pair this package with an authentication method:
|
|
97
|
+
|
|
98
|
+
- `plain-passwords` - Username/password authentication
|
|
99
|
+
- `plain-oauth` - OAuth provider authentication
|
|
100
|
+
- `plain-passkeys` (TBD) - WebAuthn/passkey authentication
|
|
101
|
+
- `plain-passlinks` (TBD) - Magic link authentication
|
|
102
|
+
|
|
103
|
+
Example with password authentication:
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
# app/urls.py
|
|
107
|
+
from plain.auth.views import LogoutView
|
|
108
|
+
from plain.urls import path
|
|
109
|
+
from plain.passwords.views import PasswordLoginView
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class LoginView(PasswordLoginView):
|
|
113
|
+
template_name = "login.html"
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
urlpatterns = [
|
|
117
|
+
path("logout/", LogoutView, name="logout"),
|
|
118
|
+
path("login/", LoginView, name="login"),
|
|
119
|
+
]
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Checking if a user is logged in
|
|
123
|
+
|
|
124
|
+
A `request.user` will either be `None` or point to an instance of your `AUTH_USER_MODEL`.
|
|
125
|
+
|
|
126
|
+
In templates:
|
|
127
|
+
|
|
128
|
+
```html
|
|
129
|
+
{% if request.user %}
|
|
130
|
+
<p>Hello, {{ request.user.email }}!</p>
|
|
131
|
+
{% else %}
|
|
132
|
+
<p>You are not logged in.</p>
|
|
133
|
+
{% endif %}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
In Python code:
|
|
137
|
+
|
|
138
|
+
```python
|
|
139
|
+
if request.user:
|
|
140
|
+
print(f"Hello, {request.user.email}!")
|
|
141
|
+
else:
|
|
142
|
+
print("You are not logged in.")
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Restricting views
|
|
146
|
+
|
|
147
|
+
Use the [`AuthViewMixin`](./views.py#AuthViewMixin) to restrict views to logged-in users, admin users, or custom logic:
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
from plain.auth.views import AuthViewMixin
|
|
151
|
+
from plain.exceptions import PermissionDenied
|
|
152
|
+
from plain.views import View
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
class LoggedInView(AuthViewMixin, View):
|
|
156
|
+
login_required = True
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
class AdminOnlyView(AuthViewMixin, View):
|
|
160
|
+
login_required = True
|
|
161
|
+
admin_required = True
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
class CustomPermissionView(AuthViewMixin, View):
|
|
165
|
+
def check_auth(self):
|
|
166
|
+
super().check_auth()
|
|
167
|
+
if not self.request.user.is_special:
|
|
168
|
+
raise PermissionDenied("You're not special!")
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
The [`AuthViewMixin`](./views.py#AuthViewMixin) provides:
|
|
172
|
+
|
|
173
|
+
- `login_required` - Requires a logged-in user
|
|
174
|
+
- `admin_required` - Requires `user.is_admin` to be True
|
|
175
|
+
- `check_auth()` - Override for custom authorization logic
|
|
176
|
+
|
|
177
|
+
## Installation
|
|
178
|
+
|
|
179
|
+
Install the `plain.auth` package from [PyPI](https://pypi.org/project/plain.auth/):
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
uv add plain.auth
|
|
183
|
+
```
|
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# plain-auth changelog
|
|
2
2
|
|
|
3
|
+
## [0.17.0](https://github.com/dropseed/plain/releases/plain-auth@0.17.0) (2025-09-12)
|
|
4
|
+
|
|
5
|
+
### What's changed
|
|
6
|
+
|
|
7
|
+
- Model managers are now accessed via `.query` instead of `.objects` ([037a239](https://github.com/dropseed/plain/commit/037a239ef4))
|
|
8
|
+
- Updated to require Python 3.13 minimum ([d86e307](https://github.com/dropseed/plain/commit/d86e307efb))
|
|
9
|
+
|
|
10
|
+
### Upgrade instructions
|
|
11
|
+
|
|
12
|
+
- Replace any usage of `Model.objects` with `Model.query` in your code (e.g., `User.objects.get()` becomes `User.query.get()`)
|
|
13
|
+
|
|
14
|
+
## [0.16.0](https://github.com/dropseed/plain/releases/plain-auth@0.16.0) (2025-08-19)
|
|
15
|
+
|
|
16
|
+
### What's changed
|
|
17
|
+
|
|
18
|
+
- Removed automatic CSRF token rotation on login as part of CSRF system refactor using Sec-Fetch-Site headers ([9551508](https://github.com/dropseed/plain/commit/955150800c))
|
|
19
|
+
- Updated README with improved documentation, examples, and better package description ([4ebecd1](https://github.com/dropseed/plain/commit/4ebecd1856))
|
|
20
|
+
|
|
21
|
+
### Upgrade instructions
|
|
22
|
+
|
|
23
|
+
- No changes required
|
|
24
|
+
|
|
3
25
|
## [0.15.0](https://github.com/dropseed/plain/releases/plain-auth@0.15.0) (2025-07-22)
|
|
4
26
|
|
|
5
27
|
### What's changed
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# plain.auth
|
|
2
|
+
|
|
3
|
+
**Add users to your app and decide what they can access.**
|
|
4
|
+
|
|
5
|
+
- [Overview](#overview)
|
|
6
|
+
- [Authentication setup](#authentication-setup)
|
|
7
|
+
- [Settings configuration](#settings-configuration)
|
|
8
|
+
- [Creating a user model](#creating-a-user-model)
|
|
9
|
+
- [Login views](#login-views)
|
|
10
|
+
- [Checking if a user is logged in](#checking-if-a-user-is-logged-in)
|
|
11
|
+
- [Restricting views](#restricting-views)
|
|
12
|
+
- [Installation](#installation)
|
|
13
|
+
|
|
14
|
+
## Overview
|
|
15
|
+
|
|
16
|
+
The `plain.auth` package provides user authentication and authorization for Plain applications. Here's a basic example of checking if a user is logged in:
|
|
17
|
+
|
|
18
|
+
```python
|
|
19
|
+
# In a view
|
|
20
|
+
if request.user:
|
|
21
|
+
print(f"Hello, {request.user.email}!")
|
|
22
|
+
else:
|
|
23
|
+
print("You are not logged in.")
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
And restricting a view to logged-in users:
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
from plain.auth.views import AuthViewMixin
|
|
30
|
+
from plain.views import View
|
|
31
|
+
|
|
32
|
+
class ProfileView(AuthViewMixin, View):
|
|
33
|
+
login_required = True
|
|
34
|
+
|
|
35
|
+
def get(self):
|
|
36
|
+
return f"Welcome, {self.request.user.email}!"
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Authentication setup
|
|
40
|
+
|
|
41
|
+
### Settings configuration
|
|
42
|
+
|
|
43
|
+
Configure your authentication settings in `app/settings.py`:
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
INSTALLED_PACKAGES = [
|
|
47
|
+
# ...
|
|
48
|
+
"plain.auth",
|
|
49
|
+
"plain.sessions",
|
|
50
|
+
"plain.passwords", # Or another auth method
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
MIDDLEWARE = [
|
|
54
|
+
"plain.sessions.middleware.SessionMiddleware",
|
|
55
|
+
"plain.auth.middleware.AuthenticationMiddleware",
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
AUTH_USER_MODEL = "users.User"
|
|
59
|
+
AUTH_LOGIN_URL = "login"
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Creating a user model
|
|
63
|
+
|
|
64
|
+
Create your own user model using `plain create users` or manually:
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
# app/users/models.py
|
|
68
|
+
from plain import models
|
|
69
|
+
from plain.passwords.models import PasswordField
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class User(models.Model):
|
|
73
|
+
email = models.EmailField()
|
|
74
|
+
password = PasswordField()
|
|
75
|
+
is_admin = models.BooleanField(default=False)
|
|
76
|
+
created_at = models.DateTimeField(auto_now_add=True)
|
|
77
|
+
|
|
78
|
+
def __str__(self):
|
|
79
|
+
return self.email
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Login views
|
|
83
|
+
|
|
84
|
+
To log users in, you'll need to pair this package with an authentication method:
|
|
85
|
+
|
|
86
|
+
- `plain-passwords` - Username/password authentication
|
|
87
|
+
- `plain-oauth` - OAuth provider authentication
|
|
88
|
+
- `plain-passkeys` (TBD) - WebAuthn/passkey authentication
|
|
89
|
+
- `plain-passlinks` (TBD) - Magic link authentication
|
|
90
|
+
|
|
91
|
+
Example with password authentication:
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
# app/urls.py
|
|
95
|
+
from plain.auth.views import LogoutView
|
|
96
|
+
from plain.urls import path
|
|
97
|
+
from plain.passwords.views import PasswordLoginView
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class LoginView(PasswordLoginView):
|
|
101
|
+
template_name = "login.html"
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
urlpatterns = [
|
|
105
|
+
path("logout/", LogoutView, name="logout"),
|
|
106
|
+
path("login/", LoginView, name="login"),
|
|
107
|
+
]
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Checking if a user is logged in
|
|
111
|
+
|
|
112
|
+
A `request.user` will either be `None` or point to an instance of your `AUTH_USER_MODEL`.
|
|
113
|
+
|
|
114
|
+
In templates:
|
|
115
|
+
|
|
116
|
+
```html
|
|
117
|
+
{% if request.user %}
|
|
118
|
+
<p>Hello, {{ request.user.email }}!</p>
|
|
119
|
+
{% else %}
|
|
120
|
+
<p>You are not logged in.</p>
|
|
121
|
+
{% endif %}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
In Python code:
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
if request.user:
|
|
128
|
+
print(f"Hello, {request.user.email}!")
|
|
129
|
+
else:
|
|
130
|
+
print("You are not logged in.")
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Restricting views
|
|
134
|
+
|
|
135
|
+
Use the [`AuthViewMixin`](./views.py#AuthViewMixin) to restrict views to logged-in users, admin users, or custom logic:
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
from plain.auth.views import AuthViewMixin
|
|
139
|
+
from plain.exceptions import PermissionDenied
|
|
140
|
+
from plain.views import View
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class LoggedInView(AuthViewMixin, View):
|
|
144
|
+
login_required = True
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
class AdminOnlyView(AuthViewMixin, View):
|
|
148
|
+
login_required = True
|
|
149
|
+
admin_required = True
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
class CustomPermissionView(AuthViewMixin, View):
|
|
153
|
+
def check_auth(self):
|
|
154
|
+
super().check_auth()
|
|
155
|
+
if not self.request.user.is_special:
|
|
156
|
+
raise PermissionDenied("You're not special!")
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
The [`AuthViewMixin`](./views.py#AuthViewMixin) provides:
|
|
160
|
+
|
|
161
|
+
- `login_required` - Requires a logged-in user
|
|
162
|
+
- `admin_required` - Requires `user.is_admin` to be True
|
|
163
|
+
- `check_auth()` - Override for custom authorization logic
|
|
164
|
+
|
|
165
|
+
## Installation
|
|
166
|
+
|
|
167
|
+
Install the `plain.auth` package from [PyPI](https://pypi.org/project/plain.auth/):
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
uv add plain.auth
|
|
171
|
+
```
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
from plain.csrf.middleware import rotate_token
|
|
2
1
|
from plain.exceptions import ImproperlyConfigured
|
|
3
2
|
from plain.models import models_registry
|
|
4
3
|
from plain.runtime import settings
|
|
@@ -76,7 +75,6 @@ def login(request, user):
|
|
|
76
75
|
request.session[USER_HASH_SESSION_KEY] = session_auth_hash
|
|
77
76
|
if hasattr(request, "user"):
|
|
78
77
|
request.user = user
|
|
79
|
-
rotate_token(request)
|
|
80
78
|
|
|
81
79
|
|
|
82
80
|
def logout(request):
|
|
@@ -117,7 +115,7 @@ def get_user(request):
|
|
|
117
115
|
|
|
118
116
|
UserModel = get_user_model()
|
|
119
117
|
try:
|
|
120
|
-
user = UserModel.
|
|
118
|
+
user = UserModel.query.get(id=request.session[USER_ID_SESSION_KEY])
|
|
121
119
|
except UserModel.DoesNotExist:
|
|
122
120
|
return None
|
|
123
121
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "plain.auth"
|
|
3
|
-
version = "0.
|
|
4
|
-
description = "
|
|
3
|
+
version = "0.17.0"
|
|
4
|
+
description = "Add users to your app and decide what they can access."
|
|
5
5
|
authors = [{name = "Dave Gaeddert", email = "dave.gaeddert@dropseed.dev"}]
|
|
6
6
|
readme = "README.md"
|
|
7
|
-
requires-python = ">=3.
|
|
7
|
+
requires-python = ">=3.13"
|
|
8
8
|
dependencies = [
|
|
9
9
|
"plain<1.0.0",
|
|
10
10
|
"plain.models<1.0.0",
|
|
@@ -22,7 +22,7 @@ def test_admin_required(db):
|
|
|
22
22
|
# login required first
|
|
23
23
|
assert client.get("/admin/").status_code == 302
|
|
24
24
|
|
|
25
|
-
user = get_user_model().
|
|
25
|
+
user = get_user_model().query.create(username="user")
|
|
26
26
|
client.force_login(user)
|
|
27
27
|
# not admin -> 404
|
|
28
28
|
assert client.get("/admin/").status_code == 404
|
plain_auth-0.15.0/PKG-INFO
DELETED
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: plain.auth
|
|
3
|
-
Version: 0.15.0
|
|
4
|
-
Summary: User authentication and authorization for Plain.
|
|
5
|
-
Author-email: Dave Gaeddert <dave.gaeddert@dropseed.dev>
|
|
6
|
-
License-File: LICENSE
|
|
7
|
-
Requires-Python: >=3.11
|
|
8
|
-
Requires-Dist: plain-models<1.0.0
|
|
9
|
-
Requires-Dist: plain-sessions<1.0.0
|
|
10
|
-
Requires-Dist: plain<1.0.0
|
|
11
|
-
Description-Content-Type: text/markdown
|
|
12
|
-
|
|
13
|
-
# plain.auth
|
|
14
|
-
|
|
15
|
-
Add users to your app and define which views they can access.
|
|
16
|
-
|
|
17
|
-
To log a user in, you'll want to pair this package with:
|
|
18
|
-
|
|
19
|
-
- `plain-passwords`
|
|
20
|
-
- `plain-oauth`
|
|
21
|
-
- `plain-passkeys` (TBD)
|
|
22
|
-
- `plain-passlinks` (TBD)
|
|
23
|
-
|
|
24
|
-
## Installation
|
|
25
|
-
|
|
26
|
-
```python
|
|
27
|
-
# app/settings.py
|
|
28
|
-
INSTALLED_PACKAGES = [
|
|
29
|
-
# ...
|
|
30
|
-
"plain.auth",
|
|
31
|
-
"plain.sessions",
|
|
32
|
-
"plain.passwords",
|
|
33
|
-
]
|
|
34
|
-
|
|
35
|
-
MIDDLEWARE = [
|
|
36
|
-
"plain.sessions.middleware.SessionMiddleware",
|
|
37
|
-
"plain.auth.middleware.AuthenticationMiddleware",
|
|
38
|
-
]
|
|
39
|
-
|
|
40
|
-
AUTH_USER_MODEL = "users.User"
|
|
41
|
-
AUTH_LOGIN_URL = "login"
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
Create your own user model (`plain create users`).
|
|
45
|
-
|
|
46
|
-
```python
|
|
47
|
-
# app/users/models.py
|
|
48
|
-
from plain import models
|
|
49
|
-
from plain.passwords.models import PasswordField
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
class User(models.Model):
|
|
53
|
-
email = models.EmailField()
|
|
54
|
-
password = PasswordField()
|
|
55
|
-
is_admin = models.BooleanField(default=False)
|
|
56
|
-
created_at = models.DateTimeField(auto_now_add=True)
|
|
57
|
-
|
|
58
|
-
def __str__(self):
|
|
59
|
-
return self.email
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
Define your URL/view where users can log in.
|
|
63
|
-
|
|
64
|
-
```python
|
|
65
|
-
# app/urls.py
|
|
66
|
-
from plain.auth.views import LoginView, LogoutView
|
|
67
|
-
from plain.urls import include, path
|
|
68
|
-
from plain.passwords.views import PasswordLoginView
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
class LoginView(PasswordLoginView):
|
|
72
|
-
template_name = "login.html"
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
urlpatterns = [
|
|
76
|
-
path("logout/", LogoutView, name="logout"),
|
|
77
|
-
path("login/", LoginView, name="login"),
|
|
78
|
-
]
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
## Checking if a user is logged in
|
|
82
|
-
|
|
83
|
-
A `request.user` will either be `None` or point to an instance of a your `AUTH_USER_MODEL`.
|
|
84
|
-
|
|
85
|
-
So in templates you can do:
|
|
86
|
-
|
|
87
|
-
```html
|
|
88
|
-
{% if request.user %}
|
|
89
|
-
<p>Hello, {{ request.user.email }}!</p>
|
|
90
|
-
{% else %}
|
|
91
|
-
<p>You are not logged in.</p>
|
|
92
|
-
{% endif %}
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
Or in Python:
|
|
96
|
-
|
|
97
|
-
```python
|
|
98
|
-
if request.user:
|
|
99
|
-
print(f"Hello, {request.user.email}!")
|
|
100
|
-
else:
|
|
101
|
-
print("You are not logged in.")
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
## Restricting views
|
|
105
|
-
|
|
106
|
-
Use the `AuthViewMixin` to restrict views to logged in users, admin users, or custom logic.
|
|
107
|
-
|
|
108
|
-
```python
|
|
109
|
-
from plain.auth.views import AuthViewMixin
|
|
110
|
-
from plain.exceptions import PermissionDenied
|
|
111
|
-
from plain.views import View
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
class LoggedInView(AuthViewMixin, View):
|
|
115
|
-
login_required = True
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
class AdminOnlyView(AuthViewMixin, View):
|
|
119
|
-
login_required = True
|
|
120
|
-
admin_required = True
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
class CustomPermissionView(AuthViewMixin, View):
|
|
124
|
-
def check_auth(self):
|
|
125
|
-
super().check_auth()
|
|
126
|
-
if not self.request.user.is_special:
|
|
127
|
-
raise PermissionDenied("You're not special!")
|
|
128
|
-
```
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
# plain.auth
|
|
2
|
-
|
|
3
|
-
Add users to your app and define which views they can access.
|
|
4
|
-
|
|
5
|
-
To log a user in, you'll want to pair this package with:
|
|
6
|
-
|
|
7
|
-
- `plain-passwords`
|
|
8
|
-
- `plain-oauth`
|
|
9
|
-
- `plain-passkeys` (TBD)
|
|
10
|
-
- `plain-passlinks` (TBD)
|
|
11
|
-
|
|
12
|
-
## Installation
|
|
13
|
-
|
|
14
|
-
```python
|
|
15
|
-
# app/settings.py
|
|
16
|
-
INSTALLED_PACKAGES = [
|
|
17
|
-
# ...
|
|
18
|
-
"plain.auth",
|
|
19
|
-
"plain.sessions",
|
|
20
|
-
"plain.passwords",
|
|
21
|
-
]
|
|
22
|
-
|
|
23
|
-
MIDDLEWARE = [
|
|
24
|
-
"plain.sessions.middleware.SessionMiddleware",
|
|
25
|
-
"plain.auth.middleware.AuthenticationMiddleware",
|
|
26
|
-
]
|
|
27
|
-
|
|
28
|
-
AUTH_USER_MODEL = "users.User"
|
|
29
|
-
AUTH_LOGIN_URL = "login"
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
Create your own user model (`plain create users`).
|
|
33
|
-
|
|
34
|
-
```python
|
|
35
|
-
# app/users/models.py
|
|
36
|
-
from plain import models
|
|
37
|
-
from plain.passwords.models import PasswordField
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
class User(models.Model):
|
|
41
|
-
email = models.EmailField()
|
|
42
|
-
password = PasswordField()
|
|
43
|
-
is_admin = models.BooleanField(default=False)
|
|
44
|
-
created_at = models.DateTimeField(auto_now_add=True)
|
|
45
|
-
|
|
46
|
-
def __str__(self):
|
|
47
|
-
return self.email
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
Define your URL/view where users can log in.
|
|
51
|
-
|
|
52
|
-
```python
|
|
53
|
-
# app/urls.py
|
|
54
|
-
from plain.auth.views import LoginView, LogoutView
|
|
55
|
-
from plain.urls import include, path
|
|
56
|
-
from plain.passwords.views import PasswordLoginView
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
class LoginView(PasswordLoginView):
|
|
60
|
-
template_name = "login.html"
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
urlpatterns = [
|
|
64
|
-
path("logout/", LogoutView, name="logout"),
|
|
65
|
-
path("login/", LoginView, name="login"),
|
|
66
|
-
]
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
## Checking if a user is logged in
|
|
70
|
-
|
|
71
|
-
A `request.user` will either be `None` or point to an instance of a your `AUTH_USER_MODEL`.
|
|
72
|
-
|
|
73
|
-
So in templates you can do:
|
|
74
|
-
|
|
75
|
-
```html
|
|
76
|
-
{% if request.user %}
|
|
77
|
-
<p>Hello, {{ request.user.email }}!</p>
|
|
78
|
-
{% else %}
|
|
79
|
-
<p>You are not logged in.</p>
|
|
80
|
-
{% endif %}
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
Or in Python:
|
|
84
|
-
|
|
85
|
-
```python
|
|
86
|
-
if request.user:
|
|
87
|
-
print(f"Hello, {request.user.email}!")
|
|
88
|
-
else:
|
|
89
|
-
print("You are not logged in.")
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
## Restricting views
|
|
93
|
-
|
|
94
|
-
Use the `AuthViewMixin` to restrict views to logged in users, admin users, or custom logic.
|
|
95
|
-
|
|
96
|
-
```python
|
|
97
|
-
from plain.auth.views import AuthViewMixin
|
|
98
|
-
from plain.exceptions import PermissionDenied
|
|
99
|
-
from plain.views import View
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
class LoggedInView(AuthViewMixin, View):
|
|
103
|
-
login_required = True
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
class AdminOnlyView(AuthViewMixin, View):
|
|
107
|
-
login_required = True
|
|
108
|
-
admin_required = True
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
class CustomPermissionView(AuthViewMixin, View):
|
|
112
|
-
def check_auth(self):
|
|
113
|
-
super().check_auth()
|
|
114
|
-
if not self.request.user.is_special:
|
|
115
|
-
raise PermissionDenied("You're not special!")
|
|
116
|
-
```
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|