module ApplicationCable
class Connection < ActionCable::Connection::Base
identified_by :current_user
def connect
#puts params[:auth_token]
self.current_user = find_verified_user
logger.add_tags 'ActionCable', current_user.name
end
end
end
アクションケーブルのエンドポイントとしてwebを使用していないので、auth_tokenを認証に使用したいと思います。デフォルトでは、アクションケーブルは認証にセッションユーザーIDを使用します。接続メソッドにパラメーターを渡す方法は?
認証トークンをクエリパラメータとして送信できました。
JavaScriptアプリでコンシューマーを作成するとき、次のようにケーブルサーバーのURLでトークンを渡します。
wss://myapp.com/cable?token=1234
私のケーブル接続では、request.params
にアクセスすることでこれを取得できますtoken
:
module ApplicationCable
class Connection < ActionCable::Connection::Base
identified_by :current_user
def connect
self.current_user = find_verified_user
logger.add_tags 'ActionCable', current_user.name
end
protected:
def find_verified_user
if current_user = User.find_by(token: request.params[:token])
current_user
else
reject_unauthorized_connection
end
end
end
end
明らかに理想的ではありませんが、WebSocketを作成するときにカスタムヘッダーを送信できないと思います。
ピエールの答え 機能します。ただし、アプリケーションでこれらのパラメーターを期待することについて明示することは良い考えです。
たとえば、構成ファイルの1つ(例:application.rb
、development.rb
など...)これを行うことができます:
config.action_cable.mount_path = '/cable/:token'
そして、あなたのConnection
クラスからそれにアクセスするだけです:
request.params[:token]
残念ながらWebSocket接続では、追加のヘッダーとカスタムヘッダーはサポートされていません1 ほとんどで2 websocketクライアントおよびサーバー。したがって、可能なオプションは次のとおりです。
URLパラメータとしてアタッチし、サーバーで解析する
path.to.api/cable?token=1234
# and parse it like
request.params[:token]
短所:ログに記録され、サーバーにアクセスできる他のユーザーが利用できるシステムプロセス情報が増える可能性があるため、脆弱性がある ここ
解決策:トークンを暗号化して添付するため、ログで確認できたとしても、復号化されるまでは意味がありません。
クライアント側:
# Append jwt to protocols
new WebSocket(url, existing_protocols.concat(jwt))
これを行うReact
およびReact-Native
のJSライブラリ action-cable-react-jwt を作成しました。お気軽にご利用ください。
サーバ側:
# get the user by
# self.current_user = find_verified_user
def find_verified_user
begin
header_array = self.request.headers[:HTTP_SEC_WEBSOCKET_PROTOCOL].split(',')
token = header_array[header_array.length-1]
decoded_token = JWT.decode token, Rails.application.secrets.secret_key_base, true, { :algorithm => 'HS256' }
if (current_user = User.find((decoded_token[0])['sub']))
current_user
else
reject_unauthorized_connection
end
rescue
reject_unauthorized_connection
end
end
1 ほとんどのWebsocket API( Mozilla's を含む)は以下のものと同じです:
WebSocketコンストラクターは、1つの必須パラメーターと1つのオプションパラメーターを受け入れます。
WebSocket WebSocket( in DOMString url, in optional DOMString protocols ); WebSocket WebSocket( in DOMString url, in optional DOMString[] protocols );
url
接続するURL。これは、WebSocketサーバーが応答するURLである必要があります。
protocols
オプション単一のプロトコル文字列またはプロトコル文字列の配列。これらの文字列はサブプロトコルを示すために使用されるため、単一のサーバーで複数のWebSocketサブプロトコルを実装できます(たとえば、1つのサーバーで、指定したプロトコルに応じて異なるタイプの対話を処理できるようにする場合があります)。プロトコル文字列を指定しない場合、空の文字列が想定されます。
2 常に例外があります。たとえば、このnode.js lib ws はカスタムヘッダーの作成を許可するため、通常のAuthorization: Bearer token
ヘッダーを使用してサーバー上で解析できますが、クライアントとサーバーの両方で解析できますws
を使用する必要があります。
すでにコメントで述べたように、受け入れられた答えは良いアイデアではありません、これは、慣例により、URLは禁止されているためですそのような機密データを含む。詳細については、こちらをご覧ください: https://tools.ietf.org/html/rfc6750#section-5. (ただし、これは特にOAuthに関するものです)。
ただし、別のアプローチがあります:ws urlを介してHTTP基本認証を使用します。ほとんどのWebSocketクライアントでは、URLの先頭に次のようにhttp基本認証を付加することで、ヘッダーを暗黙的に設定できることがわかりました:_wss://user:[email protected]/cable
_。
これにより、_Authorization
ヘッダーに_Basic ...
_の値が追加されます。私の場合、私は devise を devise-jwt と一緒に使用していて、jwtをAuthorization
ヘッダー。だから私は次のようにURLを設定します:_wss://[email protected]/cable
_ヘッダーをこれに設定します(疑似):Basic base64("token:")
そして戦略でそれを解析します。
以前の回答に追加するには、JWTをパラメーターとして使用した場合、少なくともbtoa(your_token)
@jsおよびBase64.decode64(request.params[:token])
@Rails as Railsはドット「。」を区切り文字と見なすため、トークンは@Railsのparams側で切り捨てられます
もう1つの方法(最後に他の答えではなくそれを行った方法)は、チャンネルでauthenticate
アクションを実行することです。これを使用して現在のユーザーを特定し、接続/チャネルに設定しました。すべてのものはWebSocketを介して送信されるため、暗号化されている場合(つまり、wss
)、資格情報はここでは問題になりません。
ActionCable.createCustomerを使用したい場合。しかし、私と同じように再生可能なトークンを持っています:
const consumer = ActionCable.createConsumer("/cable")
const consumer_url = consumer.url
Object.defineProperty(
consumer,
'url',
{
get: function() {
const token = localStorage.getItem('auth-token')
const email = localStorage.getItem('auth-email')
return consumer_url+"?email="+email+"&token="+token
}
});
return consumer;
その後、接続が失われた場合は、新しい新しいトークンで開かれます。
Pierre's answer のセキュリティについて:暗号化にSSLを使用するWSSプロトコルを使用している場合、安全なデータを送信するための原則はHTTPSと同じです。 SSLを使用する場合、クエリ文字列パラメーターとリクエストの本文が暗号化されます。したがって、HTTP APIでHTTPSを介してあらゆる種類のトークンを送信し、それが安全であると考える場合、WSSでも同じである必要があります。 HTTPSの場合と同様に、リクエストのURLがサーバーにログオンしてパスワードとともに保存される可能性があるため、クエリパラメータを介してパスワードなどの資格情報を送信しないでください。代わりに、サーバーが発行するトークンなどを使用します。
また、これを確認することもできます(これは基本的にJWT認証+ IPアドレス検証のようなものを説明しています) https://devcenter.heroku.com/articles/websocket-security#authentication-authorization 。