Skip to content

Commit

Permalink
[Refact] Change the methode of handshaking in websocket using a jwt m…
Browse files Browse the repository at this point in the history
…iddleware
  • Loading branch information
zakarm committed May 2, 2024
1 parent 4745017 commit b2fba28
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 99 deletions.
65 changes: 6 additions & 59 deletions app/back-end/dashboards/consumers.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
from channels.db import database_sync_to_async
from authentication.models import User
from django.db.models import F

@database_sync_to_async
def get_user(user_id):
try:
Expand All @@ -34,73 +33,21 @@ def update_user_offline(user_id):
except User.DoesNotExist:
pass

async def send_online_notification(self, user_id):
await self.channel_layer.group_send(
"online_users",
{
"type": "send_online_notification",
"user_id": user_id,
}
)

async def send_online_notification_to_socket(self, event):
user_id = event["user_id"]
user = await get_user(user_id)
await self.send(text_data=json.dumps({
"type": "online_notification",
"user": {
"id": user.id,
"username": user.username,
"image_url": user.image_url,
# Add any other relevant user data
}
}))

async def send_online_notification(self, event):
await self.send_online_notification_to_socket(event)

class UserStatusConsumer(AsyncWebsocketConsumer):
async def connect(self):
auth_headers = self.scope.get("headers", [])
auth_header = None
for header in auth_headers:
if header[0].decode() == "access":
auth_header = header[1].decode()
break
if auth_header:
try:
access_token = AccessToken(auth_header)
user_id = access_token.payload["user_id"]
print(user_id, file = sys.stderr)
self.user = get_user(user_id)
self.user_id = user_id
await self.accept()
await update_user_online(self.user_id)
await self.send_online_notification(self.user_id) # Send online notification
await self.channel_layer.group_add(
"online_users",
self.channel_name
)
except Exception as e:
print(f"Authentication error: {e}", file=sys.stderr)
await self.close()
else:
print("Anonymous user", file=sys.stderr)
await self.accept()
await update_user_online(self.scope['user'].id)
await self.accept()

async def disconnect(self, close_code):
await self.channel_layer.group_discard(
"online_users",
self.channel_name
)
await update_user_offline(self.user_id)
await update_user_offline(self.scope['user'].id)

async def receive(self, text_data):
if self.user:
user = self.scope['user']
if user:
try:
text_data_json = json.loads(text_data)
if text_data_json.get("action") == "get_friends":
data = await get_friends(self.user_id)
data = await get_friends(user.id)
await self.send(text_data=json.dumps({
"friends": data
}))
Expand Down
2 changes: 2 additions & 0 deletions app/back-end/dashboards/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,7 @@ class Friendship(models.Model):
user_to = models.ForeignKey('authentication.User', models.DO_NOTHING,
db_column='user_to', related_name = "user_to_set")
is_accepted = models.BooleanField(default=False)
u_one_is_blocked_u_two = models.BooleanField(default=False)
u_two_is_blocked_u_one = models.BooleanField(default=False)
class Meta:
db_table = 'Friendship'
4 changes: 3 additions & 1 deletion app/back-end/ft_transcendence/asgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,19 @@
from django.core.asgi import get_asgi_application
from dashboards import routing as dashboard_routing
from game import routing as game_routing
from django_channels_jwt_auth_middleware.auth import JWTAuthMiddlewareStack

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ft_transcendence.settings')
django.setup()

application = ProtocolTypeRouter({
'http': get_asgi_application(),
'websocket':
'websocket': JWTAuthMiddlewareStack(
URLRouter
(
dashboard_routing.websocket_urlpatterns
+
game_routing.websocket_urlpatterns
)
)
})
2 changes: 1 addition & 1 deletion app/back-end/ft_transcendence/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@
}

SIMPLE_JWT = {
"ACCESS_TOKEN_LIFETIME": timedelta(minutes=60),
"ACCESS_TOKEN_LIFETIME": timedelta(days=30),
"REFRESH_TOKEN_LIFETIME": timedelta(days=1),
"ROTATE_REFRESH_TOKENS": False,
"BLACKLIST_AFTER_ROTATION": False,
Expand Down
1 change: 1 addition & 0 deletions app/back-end/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ channels
faker
asgi_redis
channels_redis
django-channels-jwt-auth-middleware
110 changes: 72 additions & 38 deletions app/front-end/src/components/authChecker.tsx
Original file line number Diff line number Diff line change
@@ -1,52 +1,86 @@
"use client"

import React, { useEffect, useState } from 'react';
import { useRouter } from 'next/navigation';
import Cookies from 'js-cookie';
import Spinner from 'react-bootstrap/Spinner'
import styles from './styles/authChecker.module.css'


const AuthChecker = ({ children }: { children: React.ReactNode }) => {
const router = useRouter();
const [isAuthenticated, setIsAuthenticated] = useState<boolean | null>(null);
const router = useRouter();
const [isAuthenticated, setIsAuthenticated] = useState<boolean | null>(null);
const [socket, setSocket] = useState<WebSocket | null>(null);
const [onlineUsers, setOnlineUsers] = useState<{ id: number; username: string }[]>([]);

useEffect(() => {
const authentication = async () => {
const access = Cookies.get('access');
console.log(access)
if (access) {
const response = await fetch('http://localhost:8000/api/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ token: access })
});
if (response.ok) {
setIsAuthenticated(true);
} else {
setIsAuthenticated(false);
router.push('/sign-in');
}
useEffect(() => {
const authentication = async () => {
const access = Cookies.get('access');
console.log(access)
if (access) {
const response = await fetch('http://localhost:8000/api/verify', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ token: access })
});
if (response.ok) {
setIsAuthenticated(true);
const newSocket = new WebSocket(`ws://localhost:8000/ws/user-status?token=${access}`);
newSocket.addEventListener('open', () => {
newSocket.send(JSON.stringify({ access: access }));
newSocket.send(JSON.stringify({ action: 'get_friends' }));
});
newSocket.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
if (data.type === 'online_users') {
setOnlineUsers(data.users);
} else if (data.type === 'online_notification') {
setOnlineUsers((prevUsers) => [...prevUsers, data.user]);
}
else
{
setIsAuthenticated(false);
router.push('/sign-in');
}
};
authentication();
}, []);
});
setSocket(newSocket);
} else {
setIsAuthenticated(false);
router.push('/sign-in');
}
} else {
setIsAuthenticated(false);
router.push('/sign-in');
}
};
authentication();
}, []);

useEffect(() => {
return () => {
if (socket) {
socket.close();
}
};
}, [socket]);

if (isAuthenticated === null) {
return (
<div className={`${styles.spinnerContainer} ${styles.darkBackground}`}>
<Spinner animation="border" variant="danger" />
<p className={`${styles.loadingMessage} valo-font`}>LOADING ...</p>
</div>
);
}
if (isAuthenticated === null) {
return (
<div className={`${styles.spinnerContainer} ${styles.darkBackground}`}>
<Spinner animation="border" variant="danger" />
<p className={`${styles.loadingMessage} valo-font`}>LOADING ...</p>
</div>
);
}

return isAuthenticated ? <>{children}</> : null;
return isAuthenticated ? (
<>
{children}
<div>
<h2>Online Users</h2>
<ul>
{onlineUsers.map((user) => (
<li key={user.id}>{user.username}</li>
))}
</ul>
</div>
</>
) : null;
};

export default AuthChecker;
export default AuthChecker;

0 comments on commit b2fba28

Please sign in to comment.