refreshing and replacing old user data
This commit is contained in:
parent
5a486de8f4
commit
25c168a982
@ -51,7 +51,8 @@ class DiscordAuthenticationBackend(BaseBackend):
|
|||||||
|
|
||||||
if existing_user:
|
if existing_user:
|
||||||
# The previous access token may have expired, so update it.
|
# The previous access token may have expired, so update it.
|
||||||
existing_user.access_token = discord_user_data["access_token"]
|
existing_user.update(discord_user_data)
|
||||||
|
# existing_user.access_token = discord_user_data["access_token"]
|
||||||
existing_user.save()
|
existing_user.save()
|
||||||
return existing_user
|
return existing_user
|
||||||
|
|
||||||
|
@ -46,6 +46,7 @@ class DiscordUserOAuth2Manager(BaseUserManager):
|
|||||||
mfa_enabled=user["mfa_enabled"],
|
mfa_enabled=user["mfa_enabled"],
|
||||||
access_token=user["access_token"],
|
access_token=user["access_token"],
|
||||||
token_expires=user["token_expires"],
|
token_expires=user["token_expires"],
|
||||||
|
refresh_token=user["refresh_token"],
|
||||||
**extra_fields
|
**extra_fields
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
# Generated by Django 5.0.4 on 2024-05-31 22:41
|
# Generated by Django 5.0.4 on 2024-05-31 22:41
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
from django.utils import timezone
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
@ -13,7 +14,7 @@ class Migration(migrations.Migration):
|
|||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='discorduser',
|
model_name='discorduser',
|
||||||
name='token_expires',
|
name='token_expires',
|
||||||
field=models.DateTimeField(default=0, help_text='when to request a new access token.', verbose_name='token expires'),
|
field=models.DateTimeField(default=timezone.now, help_text='when to request a new access token.', verbose_name='token expires'),
|
||||||
preserve_default=False,
|
preserve_default=False,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
# Generated by Django 5.0.4 on 2024-06-01 16:45
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('authentication', '0002_discorduser_token_expires'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='discorduser',
|
||||||
|
name='refresh_token',
|
||||||
|
field=models.CharField(default='1', help_text='token for the application to request a new access token.', max_length=100, verbose_name='refresh token'),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
]
|
@ -1,5 +1,7 @@
|
|||||||
# -*- encoding: utf-8 -*-
|
# -*- encoding: utf-8 -*-
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
@ -7,6 +9,8 @@ from django.contrib.auth.models import PermissionsMixin
|
|||||||
|
|
||||||
from .managers import DiscordUserOAuth2Manager
|
from .managers import DiscordUserOAuth2Manager
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class DiscordUser(PermissionsMixin):
|
class DiscordUser(PermissionsMixin):
|
||||||
"""
|
"""
|
||||||
@ -65,11 +69,15 @@ class DiscordUser(PermissionsMixin):
|
|||||||
max_length=100,
|
max_length=100,
|
||||||
help_text=_("token for the application to make api calls on behalf of the user.")
|
help_text=_("token for the application to make api calls on behalf of the user.")
|
||||||
)
|
)
|
||||||
|
|
||||||
token_expires = models.DateTimeField(
|
token_expires = models.DateTimeField(
|
||||||
_("token expires"),
|
_("token expires"),
|
||||||
help_text=_("when to request a new access token.")
|
help_text=_("when to request a new access token.")
|
||||||
)
|
)
|
||||||
|
refresh_token = models.CharField(
|
||||||
|
_("refresh token"),
|
||||||
|
max_length=100,
|
||||||
|
help_text=_("token for the application to request a new access token.")
|
||||||
|
)
|
||||||
|
|
||||||
# Custom Attributes
|
# Custom Attributes
|
||||||
|
|
||||||
@ -129,3 +137,23 @@ class DiscordUser(PermissionsMixin):
|
|||||||
|
|
||||||
def get_username(self):
|
def get_username(self):
|
||||||
return self.username
|
return self.username
|
||||||
|
|
||||||
|
def update(self, raw: dict):
|
||||||
|
|
||||||
|
log.debug("updating user: %s", self.username)
|
||||||
|
log.debug("raw update data: %s", raw)
|
||||||
|
log.debug("public flags: %s, %s", raw["public_flags"], type(raw["public_flags"]))
|
||||||
|
|
||||||
|
|
||||||
|
self.username=raw["username"]
|
||||||
|
self.global_name=raw["global_name"]
|
||||||
|
self.avatar=raw["avatar"]
|
||||||
|
self.public_flags=raw["public_flags"]
|
||||||
|
self.flags=raw["flags"]
|
||||||
|
self.locale=raw["locale"]
|
||||||
|
self.mfa_enabled=raw["mfa_enabled"]
|
||||||
|
self.access_token=raw["access_token"]
|
||||||
|
self.token_expires=raw["token_expires"]
|
||||||
|
self.refresh_token=raw["refresh_token"]
|
||||||
|
|
||||||
|
self.save(force_update=True)
|
||||||
|
@ -2,8 +2,10 @@
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
import requests
|
import requests
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.utils import timezone
|
||||||
from django.http import JsonResponse
|
from django.http import JsonResponse
|
||||||
from django.views.generic import View, TemplateView
|
from django.views.generic import View, TemplateView
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
@ -31,17 +33,25 @@ class DiscordLoginRedirect(View):
|
|||||||
return redirect("auth:login")
|
return redirect("auth:login")
|
||||||
|
|
||||||
code = request.GET.get("code")
|
code = request.GET.get("code")
|
||||||
access_token, token_expires = self.exchange_code_for_token(code)
|
exchange_data = self.exchange_code(code)
|
||||||
raw_user_data = self.get_raw_user_data(access_token)
|
access_token = exchange_data["access_token"]
|
||||||
raw_user_data["access_token"] = access_token
|
|
||||||
raw_user_data["token_expires"] = token_expires
|
|
||||||
|
|
||||||
|
# Get raw user data from discord
|
||||||
|
raw_user_data = self.get_raw_user_data(access_token)
|
||||||
|
|
||||||
|
# Add the token and expires datetime to the user data
|
||||||
|
token_expire_datetime = timezone.now() + timedelta(seconds=exchange_data["expires_in"])
|
||||||
|
raw_user_data["token_expires"] = token_expire_datetime
|
||||||
|
raw_user_data["access_token"] = access_token
|
||||||
|
raw_user_data["refresh_token"] = exchange_data["refresh_token"]
|
||||||
|
|
||||||
|
# authenticate (creates user if not exists) and login
|
||||||
discord_user = authenticate(request, discord_user_data=raw_user_data)
|
discord_user = authenticate(request, discord_user_data=raw_user_data)
|
||||||
login(request, discord_user)
|
login(request, discord_user)
|
||||||
|
|
||||||
return redirect("home:index")
|
return redirect("home:index")
|
||||||
|
|
||||||
def exchange_code_for_token(self, code: str) -> tuple[str, str]:
|
def exchange_code(self, code: str) -> dict:
|
||||||
"""
|
"""
|
||||||
Exchanges the given code for an access token.
|
Exchanges the given code for an access token.
|
||||||
A call is made to the Discord API.
|
A call is made to the Discord API.
|
||||||
@ -59,12 +69,27 @@ class DiscordLoginRedirect(View):
|
|||||||
headers=request_data["headers"]
|
headers=request_data["headers"]
|
||||||
)
|
)
|
||||||
|
|
||||||
resp_json = response.json()
|
return response.json()
|
||||||
log.debug(resp_json)
|
|
||||||
access_token = resp_json["access_token"]
|
|
||||||
expires = resp_json["expires"]
|
|
||||||
|
|
||||||
return access_token, expires
|
def refresh_token(self, refresh_token: str) -> dict:
|
||||||
|
"""
|
||||||
|
Refresh the access token if expired, using the refresh
|
||||||
|
token. Returns a new access token, expire time and refresh
|
||||||
|
token.
|
||||||
|
"""
|
||||||
|
|
||||||
|
request_data = settings.DISCORD_REFRESH_TOKEN_REQUEST
|
||||||
|
request_data["data"]["refresh_token"] = refresh_token
|
||||||
|
|
||||||
|
log.debug("request data: %s", request_data)
|
||||||
|
|
||||||
|
response = requests.post(
|
||||||
|
url=f"{settings.DISCORD_API_URL}/oauth2/token",
|
||||||
|
data=request_data["data"],
|
||||||
|
headers=request_data["headers"]
|
||||||
|
)
|
||||||
|
|
||||||
|
return response.json()
|
||||||
|
|
||||||
def get_raw_user_data(self, access_token: str):
|
def get_raw_user_data(self, access_token: str):
|
||||||
"""
|
"""
|
||||||
|
18
apps/home/migrations/0022_alter_subscription_filters.py
Normal file
18
apps/home/migrations/0022_alter_subscription_filters.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.0.4 on 2024-05-31 22:41
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('home', '0021_alter_subscription_filters'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='subscription',
|
||||||
|
name='filters',
|
||||||
|
field=models.ManyToManyField(blank=True, to='home.filter'),
|
||||||
|
),
|
||||||
|
]
|
@ -137,7 +137,15 @@ DISCORD_CODE_EXCHANGE_REQUEST = {
|
|||||||
"client_secret": DISCORD_SECRET,
|
"client_secret": DISCORD_SECRET,
|
||||||
"grant_type": "authorization_code",
|
"grant_type": "authorization_code",
|
||||||
"redirect_uri": env("DISCORD_REDIRECT_URL"),
|
"redirect_uri": env("DISCORD_REDIRECT_URL"),
|
||||||
"scope": " ".join(DISCORD_SCOPES)
|
"scope": " ".join(DISCORD_SCOPES),
|
||||||
|
"code": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DISCORD_REFRESH_TOKEN_REQUEST = {
|
||||||
|
"headers": {"Content-Type": "application/x-www-form-urlencoded"},
|
||||||
|
"data": {
|
||||||
|
"grant_type": "refresh_token",
|
||||||
|
"refresh_token": ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DISCORD_API_URL = env("DISCORD_API_URL")
|
DISCORD_API_URL = env("DISCORD_API_URL")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user