1.settings.py
INSTALLED_APPS = [ '...', 'channels', '...', ] ASGI_APPLICATION = 'server.routing.application' CHANNEL_LAYERS = { 'default': { 'BACKEND': 'channels_redis.core.RedisChannelLayer', 'CONFIG': { "hosts": [(os.getenv('REDIS_SERVER_HOST', '127.0.0.1'), int(os.getenv('REDIS_SERVER_PORT', '6379')))], }, }, }
2.routing.py(settin.py同级)
# -*- coding: utf-8 -*- from channels.routing import ProtocolTypeRouter, URLRouter from device.consumers import QueryAuthMiddleware # websocket中间件 import device.routing # 路由 application = ProtocolTypeRouter({ 'websocket': QueryAuthMiddleware( URLRouter( device.routing.websocket_urlpatterns ) ) })
class QueryAuthMiddleware: """ WebSocket 认证中间件 """ def __init__(self, inner): # Store the ASGI application we were passed self.inner = inner def __call__(self, scope): query = parse.parse_qs(scope["query_string"].decode()) token = query.get('token', [None])[0] device_name = None try: login_info = json.loads(base64.b64decode(token).decode()) device_name = login_info['name'] logger.info('Device {} connect from {} port {}'.format(device_name, scope['client'][0], scope['client'][1])) # 验证时间 gen_time = datetime.strptime(login_info['time'], '%Y%m%d%H%M%S') now_time = datetime.now() if abs(gen_time - now_time).total_seconds() > 5 * 60: raise ValueError('Device {} time validate fail: token time: {}, server time: {}'.format( device_name, gen_time.strftime('%Y-%m-%d %H:%M:%S'), now_time.strftime('%Y-%m-%d %H:%M:%S'))) # 验证密码 device = DeviceInfoModel.objects.get(name=device_name) # 获取到设备 correct = device.check_password(login_info['password']) # 检查密码 if not correct: raise ValueError('Device {} password validate fail'.format(device_name)) except DeviceInfoModel.DoesNotExist: logger.info('Device {} can not find in DB'.format(device_name)) device = None except Exception as e: logger.error('Connect error {}'.format(e)) device = None finally: # Middleware 中必须手动关闭数据库连接 # http://channels.readthedocs.io/en/latest/topics/authentication.html#custom-authentication close_old_connections() return self.inner(dict(scope, user=device))
参考:https://channels.readthedocs.io/en/latest/