问题
i using react as my front end and django as my backend , as such , it requires me to use token based authentication with django channels. The method i am employing is by sending the authentication token as a cookie header. The methodology was taken from this git hub post here
So far , i have gotten most of the working parts together , however i don't seem to be able to persist the connection , it will always return an error in my console:
ERR_CONNECTION_RESET
Here is my code:
FRONTEND: Websocket.js
class WebSocketService{
static instance = null;
callbacks = {};
static getInstance(){
if (!WebSocketService.instance){
WebSocketService.instance = new WebSocketService();
}
return WebSocketService.instance;
}
constructor(){
this.socketRef = null;
}
connect(token){
var loc = window.location
var wsStart = 'ws://'
if (loc.protocol === 'https'){
wsStart = 'wss://'
}
const path = wsStart + 'localhost:8000'+ loc.pathname
// console.log(path)
// console.log(path + "?token=" + token)
document.cookie = 'authorization=' + token + ';'
console.log(document.cookie)
this.socketRef = new WebSocket(path)
this.socketRef.onmessage = e => {
console.log('in on message')
this.socketNewMessage(e.data);
};
this.socketRef.onopen = () => {
console.log(this.props.token)
console.log("WebSocket open");
};
this.socketRef.onerror = e => {
console.log('error happ')
console.log(e.message);
};
this.socketRef.onclose = () => {
console.log("WebSocket closed, restarting..");
this.connect(token);
};
}
socketNewMessage(data){
const parsedData = JSON.parse(data);
const command = parsedData.command;
if(Object.keys(this.callbacks).length === 0){
return;
}
if(command === 'messages'){
this.callbacks[command](parsedData.messages);
}
if(command === 'new_message'){
console.log("okay so this was called")
this.callbacks[command](parsedData.message);
}
}
state(){
return this.socketRef.readyState;
}
waitForSocketConnection(callback){
const socket = this.socketRef;
const recursion = this.waitForSocketConnection;
setTimeout(
function(){
if(socket.readyState === 1){
console.log("Connection is made");
if(callback != null){
callback();
}
return;
}
else{
console.log("Wait for connection..");
recursion(callback);
}
}, 1);
}
}
let WebSocketInstance = WebSocketService.getInstance();
export default WebSocketInstance;
FRONTEND: Apps.js
class App extends Component {
componentDidMount() {
console.log('app mounting..')
this.props.onTryAutoSignup();
console.log(this.props.isAuthenticated)
if (this.props.isAuthenticated) {
WebSocketInstance.connect()
}
}
componentDidUpdate(oldProps) {
console.log('app updating props..')
if (this.props.token !== oldProps.token ) {
console.log(this.props.token)
WebSocketInstance.connect(this.props.token)
}
}
render() {
return (
<div>
<Router>
<CustomLayout {...this.props}>
<BaseRouter/>
</CustomLayout>
</Router>
</div>
);
}
}
const mapStateToProps = state => {
return {
isAuthenticated: state.token !== null ,
token : state.token
}
}
const mapDispatchToProps = dispatch => {
return {
onTryAutoSignup: () => dispatch(actions.authCheckState())
}
}
export default connect(mapStateToProps, mapDispatchToProps)(App);
BACKEND: token_auth.py ( A custom middleware)
@database_sync_to_async
def get_user(token_key):
try:
return Token.objects.get(key=token_key).user
except Token.DoesNotExist:
return AnonymousUser()
class TokenAuthMiddleware:
"""
Token authorization middleware for Django Channels 2
see:
https://channels.readthedocs.io/en/latest/topics/authentication.html#custom-authentication
"""
def __init__(self, inner):
self.inner = inner
def __call__(self, scope):
return TokenAuthMiddlewareInstance(scope, self)
class TokenAuthMiddlewareInstance:
def __init__(self, scope, middleware):
self.middleware = middleware
self.scope = dict(scope)
self.inner = self.middleware.inner
async def __call__(self, receive, send):
headers = dict(self.scope["headers"])
print(headers[b"cookie"])
if b"authorization" in headers[b"cookie"]:
print('still good here')
cookies = headers[b"cookie"].decode()
token_key = re.search("authorization=(.*)(; )?", cookies).group(1)
if token_key:
self.scope["user"] = await get_user(token_key)
return self.inner(self.scope)
BACKEND : Router.py
application = ProtocolTypeRouter({
"websocket": TokenAuthMiddlewareStack(
URLRouter([
path("", NotificationConsumer),
]),
),
})
TokenAuthMiddlewareStack = lambda inner: TokenAuthMiddleware(AuthMiddlewareStack(inner))
Here is my the items that were printed out in my cmd prompt:
WebSocket HANDSHAKING / [127.0.0.1:59931]
b'authorization=xxxxxxxxxxxx' #<-- token from the cookie header
still good here #<--- passed first validation
user1 #<---- went into the get_user function i declared within my middleware
WebSocket DISCONNECT / [127.0.0.1:59931] #<---- disconnects...
Please help! Im lost!
回答1:
the issue was with the middleware instance , it should be :
class TokenAuthMiddlewareInstance:
def __init__(self, scope, middleware):
self.middleware = middleware
self.scope = dict(scope)
self.inner = self.middleware.inner
async def __call__(self, receive, send):
close_old_connections()
headers = dict(self.scope["headers"])
print(headers[b"cookie"])
if b"authorization" in headers[b"cookie"]:
print('still good here')
cookies = headers[b"cookie"].decode()
token_key = re.search("authorization=(.*)(; )?", cookies).group(1)
if token_key:
self.scope["user"] = await get_user(token_key)
inner = self.inner(self.scope)
return await inner(receive, send)
TokenAuthMiddlewareStack = lambda inner: TokenAuthMiddleware(AuthMiddlewareStack(inner))
thanks!
来源:https://stackoverflow.com/questions/61413375/django-channels-custom-token-authenticated-websocket-keeps-disconnecting-err-con