django / django/channels

Trouble saving user along scope

Open
#2,121 2 comments 0 reactions 0 assignees View on GitHub
Dominant language
Python
Stars
6.4k
Forks
826
PR merge metrics
No merged PRs in 30d

Description

Developing a dashboard using Django channels, two different consumers are implemented, UserConsumer and RequestConsumer.

In UserConsumer methods like login, logout and get_user are implemented. The user Authentication is being done using OTP code sent to user mobile so that a user_send_code method is in charge of sending SMS while the user_login method verifies the code sent by user. UserConsumer is implemented as follow:

```
class UserConsumer(AsyncJsonWebsocketConsumer):

async def connect(self):
await self.accept()

async def receive_json(self, content=None, **kwargs):
action = content.get("action", "user.get_user")
if action == "user.login":
await self.user_login(content)
elif action == "user.send_code":
await self.user_send_code(content)
elif action == "user.logout":
await self.user_logout()
else:
await self.user_get_user()

async def user_send_code(self, content):
await self.send("we will send sms to: {}".format(content['mobile']))
if check_mobile_pattern(content["mobile"]):
code = random.randint(1111, 9999)
self.scope[VERIFY_CODE] = code
self.scope[MOBILE] = content["mobile"]
result = await send_sms(content["mobile"], code)
if result:
await self.send_json(send_code(200))
else:
await self.send_json(send_code(400))
else:
await self.send_json(send_code(SystemErrorCodes.InvalidMobilePattern))

async def user_get_user(self):
if self.scope['user'].is_authenticated:
await self.send_json({"id": self.scope['user'].id})
else:
await self.send_json(send_code(SystemMessageCodes.AnonymousUserMessage))

async def user_login(self, content):
verify_code = self.scope.get("verify_code")
code = content.get("code")
mobile = self.scope.get(MOBILE)
if mobile is not None and verify_code is not None and code == verify_code:
user = await load_user_by_mobile(mobile)
del self.scope[VERIFY_CODE]
# login the user to this session.
await login(self.scope, user)
# save the session (if the session backend does not access the db you can use `sync_to_async`)
await database_sync_to_async(self.scope["session"].save)()
await self.send_json(send_code(200))
else:
await self.send_json(send_code(SystemErrorCodes.InvalidVerifyCode))
```
after sending the right code to web service, user logins and user_get_user method returns the userID. However when I try to open a new Socket of class RequestConsumer, the user is not set in the scope and socket closed. Here is the code:

```
class RequestConsumer(AsyncWebsocketConsumer):

async def connect(self):
self.user = self.scope['user']
if self.user.is_authenticated:
await self.accept()
else:
await self.close()
my asgi application is implemented as follow:

application = ProtocolTypeRouter({
"http": django_asgi_app,
"websocket": AllowedHostsOriginValidator(
AuthMiddlewareStack(
URLRouter(
[
path("user/", UserConsumer.as_asgi()),
path('requests/', RequestConsumer.as_asgi()),
]
)
)
),
})
```
so both consumer are using same AuthMiddlewareStack middleware. And here is some parts of my settings.py file:

```
INSTALLED_APPS = [
'daphne',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'file_process.apps.FileProcessConfig',
'channels',
'users_app.apps.UsersAppConfig',
'requests_apps.apps.RequestsAppConfig'
]

MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

SESSION_ENGINE = 'django.contrib.sessions.backends.db' # Default session storage
SESSION_COOKIE_NAME = 'sessionid' # Default cookie name
SESSION_COOKIE_HTTPONLY = True # Prevent JavaScript access
SESSION_COOKIE_SECURE = False # Set to True if using HTTPS
SESSION_EXPIRE_AT_BROWSER_CLOSE = False
SESSION_SAVE_EVERY_REQUEST = True
```
and finally this is a sample test script I've provided for the client side:

```

const socket1 = new WebSocket("ws://localhost:8000/user/");

socket1.onopen = () => {
console.log("Login WebSocket Connected");
};

socket1.onerror = (error) => {
console.error("WebSocket Error: ", error);
};

socket1.onclose = () => {
console.log("Login WebSocket Closed");
};

socket1.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log("Message from server: ", data);

if (data.code === 200) {

const socket2 = new WebSocket("ws://localhost:8000/requests/");

socket2.onopen = () => {
console.log("Login WebSocket Connected");
};

socket2.onerror = (error) => {
console.error("WebSocket Error: ", error);
};

socket2.onclose = () => {
console.log("Login WebSocket Closed");
};

} else {
alert("Login Failed!");
}
};

document.getElementById("loginForm").addEventListener("submit", (e) => {
e.preventDefault();

const code = document.getElementById("code").value;

const message = {
action: "user.login",
code: code,
};

socket1.send(JSON.stringify(message));
});

```
I couldn't find any cookie being sent to my browser if there should be one there.

This is my first webservice developed by [django-channels](https://channels.readthedocs.io/en/latest/) so I'm not sure if I have done everything properly.

Contributor guide

Open the contributing guide

Research direction

Start with the ASGI application and AuthMiddlewareStack configuration, then compare the session handling in UserConsumer with scope['user'] in RequestConsumer. Use the provided browser script and settings.py to inspect whether the second WebSocket receives the session cookie. Done means the authenticated user is available in RequestConsumer after the login flow, or the missing session behavior is documented.

Written by the indexing model from the issue text.

Assessment

Tech stack
django, javascript, python
Domain
authentication, backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.