I am using a frontend framework (Vuejs) and django-rest-framework for the REST API in my project. Also, for JSON web token authentication I am using django-rest-framework-jwt. After a successful login, the user is provided with a token. This token is passed into every request to fetch any API related stuff.
Now I would like to integrate django channels into my project. So, after successful login, when the token is received in the client side, I would like to initiate a websocket connection. Then on the server (consumer), I would like to check if the requested user is not anonymous. If the requested user is anonymous, I would like to close the connenction or else accept it.
This is how I have till now:
client side:
const socket = new WebSocket("ws://" + "dev.site.com"+ "/chat/");
routing.py:
channel_routing = [
route("websocket.connect", ws_connect),
...
...
]
consumers:
def ws_connect(message):
# if the user is no anonymous
message.reply_channel.send({
"accept": True
})
# else
message.reply_channel.send({
"close": True
})
In the documentation there's a decorator @channel_session_user_from_http
which will provide a message.user
. But I am using a token instead of a session. How can I check a user on connection when using token authentication, so that I can accept or close connection. Or, if there is a better way could you please advise me with it. Thank you.
The problem is that the browsers do not support passing jwt auth headers on websocket upgrade, so that's basically it. I faced this problem some time ago and came up with the solution of passing the token via query parameters - note that this is totally insecure without TLS as you expose the authentication in the URI. I don't have the access to the exact code anymore, but here is the idea:
Register the consumer with
On browser side, you can establish the websocket connection by passing the token as query parameter in the websocket URI:
You can then extract the auth check code in a decorator similar to
@channel_session_user_from_http
and just decorate your connection routines, or extract the code to a mixin if you use class-based routes.I would like to repeat though that this approach is totally insecure without using encryption, so in production you URIs should start with
https/wss
.Edit: here is a pretty nice solution for DRF token auth, suitable for both function-based and class-based routes. It has pretty much the same approach as mine, constructing a request object and passing it to the authenticator.
@hoefling's answer was my guide. I was confused about two things on authenticating a user.
What to do with the token?
How validate that token and get the user?
VerifyJSONWebTokenSerializer
class was all I needed to validate the token, and get that token's user object. (Thanks @hoefling!) You can read the actual code of django-rest-framework-jwt here.So, I ended up doing this way: