# ws_authentication.pyfrom functools import wraps
from json import loads, dumps
from django.utils.translation import ugettext_lazy as _
from django.core.exceptions import ObjectDoesNotExist
from rest_framework import exceptions
from channels.handler import AsgiRequest
from multi_token.models import Token
def_close_reply_channel(message):
message.reply_channel.send({"close": True})
defauthenticate(token):"""
Tries to authenticate user based on the supplied token. It also checks
the token structure and validity.
"""try:
auth_token = Token.objects.get(key=token)
except Token.DoesNotExist:
msg = _('Invalid token')
raise exceptions.AuthenticationFailed(msg)
"""Other authenticate operation"""return auth_token.user, auth_token
defws_auth_request_token(func):"""
Checks the presence of a "token" request parameter and tries to
authenticate the user based on its content.
The request url must include token.
eg: /v1/channel/1/?token=abcdefghijklmn
"""@wraps(func)definner(message, *args, **kwargs):try:
if"method"notin message.content:
message.content['method'] = "FAKE"
request = AsgiRequest(message)
except Exception as e:
raise ValueError("Cannot parse HTTP message - are you sure this is a HTTP consumer? %s" % e)
token = request.GET.get("token", None)
print request.path,request.GET
if token isNone:
_close_reply_channel(message)
raise ValueError("Missing token request parameter. Closing channel.")
user, token = authenticate(token)
message.token = token
message.user = user
return func(message, *args, **kwargs)
return inner
defws_auth_message_token(func):"""
Checks the presence of a "token" field on the message's text field and
tries to authenticate the user based on its content.
The text must include "token" field.
eg:{'text':{'token': 'abcdefg','otherdata':''}}.
"""@wraps(func)definner(message, *args, **kwargs):
message_text = message.get('text', None)
if message_text isNone:
_close_reply_channel(message)
raise ValueError("Missing text field. Closing channel.")
try:
message_text_json = loads(message_text)
except ValueError:
_close_reply_channel(message)
raise
token = message_text_json.pop('token', None)
if token isNone:
_close_reply_channel(message)
raise ValueError("Missing token field. Closing channel.")
user, token = authenticate(token)
message.token = token
message.user = user
message.text = dumps(message_text_json)
return func(message, *args, **kwargs)
return inner
使用:
from channels import Group
from .ws_authentication import ws_auth_request_token, ws_auth_message_token
@ws_auth_request_tokendefws_connect(message, room_id):
Group("room-%s" % room_id).add(message.reply_channel)
message.reply_channel.send({"accept": True})
@ws_auth_message_tokendefws_receive(message, room_id):
message.reply_channel.send({'text': message['text']})
defws_disconnect(message,room_id):
Group("room-%s" % room_id).discard(message.reply_channel)