我有一个有角度的6应用程序和python(django 2.0.6)后端。 Angular 6应用程序是使用AWS S3和CloudFront部署的。
Angular 6应用程序使用websocket功能。 本地一切正常,但是部署Angular 6应用程序后无法通过websocket握手请求传递cookie。 (仅通过cookie对websoket连接进行授权。这样做的原因并不重要。)
位于子域“ api.site.com”上的Websocket服务器
我尝试了多种方法来在angular 6应用中设置cookie,例如:
let domain = 'api.site.com'
document.cookie = `Token=${token}; domain=${domain}; path=/`;
document.cookie = `Token=${token}; path=/`;
document.cookie = `Token=${token};
document.cookie = `Token=${token}, domain=${domain}, path=/`;
使用ngx-cookie-service
:
this.cookieService.set('Token', token, undefined, '/', 'api.site.com');
this.cookieService.set('Token', token, undefined, '/');
this.cookieService.set('Token', token);
token
是JWT令牌。
对于上述所有情况,在部署应用程序时,Token
cookie不会与websocket握手一起传递。使用wss
协议。
angular 6应用程序在域site.com
下运行(=> api
是子域)
Cloudfront行为设置为传递所有cookie。
请告知可能是什么原因。
答案 0 :(得分:1)
解决方案:
就我而言,我无法设置Cookie,但基于以下主题制定了解决方案:HTTP headers in Websockets client API
关于如何使用jwt令牌认证WebSocket客户端API的信息很多。以下是适用于django 2.0.6
,channels 2.1.1
,angular 6
堆栈的完整解决方案:
django中间件:
class TokenAuthMiddleware:
def __init__(self, inner):
self.inner = inner
def __call__(self, scope):
auth_header = None
if 'subprotocols' in scope:
try:
auth_header = scope['subprotocols'][1]
except:
pass
if auth_header:
try:
user_jwt = jwt.decode(
auth_header,
settings.SECRET_KEY,
)
scope['user'] = MyUser.objects.get(
id=user_jwt['user_id']
)
close_old_connections()
except (InvalidSignatureError, KeyError, ExpiredSignatureError, DecodeError):
scope['auth_error'] = 'KeyError'
pass
except Exception as e: # NoQA
scope['auth_error'] = 'Unknown'
return self.inner(scope)
TokenAuthMiddlewareStack = lambda inner: TokenAuthMiddleware(AuthMiddlewareStack(inner))
ws使用者:
class WsConsumer(JsonWebsocketConsumer):
def connect(self):
self.accept('auth_token')
if self._is_authenticated():
***do things***
else:
logger.error("ws client auth error")
self.close(code=4003)
def _is_authenticated(self):
if hasattr(self.scope['headers'], 'auth_error'):
return False
if type(self.scope['user']) is AnonymousUser or not self.scope['user']:
return False
return True
WebSocket客户端API(js cli):
this.socket = new WebSocket('ws://host.com/ws/`, ['auth_token', token]);