如何使用devise_token_auth和ActionCable来validation用户?

我有一个带有devise_token_auth gem身份validation的Rails 5 API。

现在我想要经过身份validation的用户进行个人聊天 我没有资产,因为我正在使用API​​,而前端是在本机应用程序中,我希望本机应用程序消息传递。

所以我如何使用devise_token_auth gemvalidation用户使用动作电缆进行个人消息传递

Rails 5 API通常不支持cookie。 请参阅: http : //guides.rubyonrails.org/api_app.html#creating-a-new-application 。

如果您在站点的某个位置(使用devise_token_auth gem)执行常见的HTTP身份validation,那么您将获得3个auth标头 – access_tokenclientuid

在这种情况下,您可以使用这些3个auth标头为您的Websockets连接使用Basic身份validation(根据https://devcenter.heroku.com/articles/websocket-security#authentication-authorization ):

致电(我使用Chrome Simple WebSocket客户端 ):

 ws://localhost:3000/cable/?access-token=ZigtvvcKK7B7rsF_20bGHg&client=TccPxBrirWOO9k5fK4l_NA&uid=client1@example.com 

然后处理:

 # Be sure to restart your server when you modify this file. Action Cable runs in an EventMachine loop that does not support auto reloading. module ApplicationCable class Connection < ActionCable::Connection::Base identified_by :current_user def connect params = request.query_parameters() access_token = params["access-token"] uid = params["uid"] client = params["client"] self.current_user = find_verified_user access_token, uid, client logger.add_tags 'ActionCable', current_user.email end protected def find_verified_user token, uid, client_id # this checks whether a user is authenticated with devise user = User.find_by email: uid # http://www.rubydoc.info/gems/devise_token_auth/0.1.38/DeviseTokenAuth%2FConcerns%2FUser:valid_token%3F if user && user.valid_token?(token, client_id) user else reject_unauthorized_connection end end end end 

这类似于常见的Websockets auth https://rubytutorial.io/actioncable-devise-authentication/

这种认证可能就足够了。 我认为没有必要在通道订阅和发送到服务器的每个Websocket消息上进行身份validation:

http://guides.rubyonrails.org/action_cable_overview.html#server-side-components-connections

对于服务器接受的每个WebSocket,都会实例化一个连接对象。 此对象成为从那里创建的所有通道订阅的父对象。 连接本身不处理除身份validation和授权之外的任何特定应用程序逻辑。

因此,如果您的连接是FooChannel < ApplicationCable::Channel identified_by :current_user ,您可以稍后在FooChannel < ApplicationCable::Channel任何位置访问current_user ! 例:

 class AppearanceChannel < ApplicationCable::Channel def subscribed stream_from "appearance_channel" if current_user ActionCable.server.broadcast "appearance_channel", { user: current_user.id, online: :on } current_user.online = true current_user.save! end end def unsubscribed if current_user # Any cleanup needed when channel is unsubscribed ActionCable.server.broadcast "appearance_channel", { user: current_user.id, online: :off } current_user.online = false current_user.save! end end end 

PS我想在Rails 5 API中使用cookies,你可以打开它:

http://guides.rubyonrails.org/api_app.html#other-middleware

配置/ application.rb中

 config.middleware.use ActionDispatch::Cookies 

http://guides.rubyonrails.org/api_app.html#adding-other-modules

控制器/ API / application_controller.rb

 class Api::ApplicationController < ActionController::API include ActionController::Cookies ... 

这里使用ng-token-auth在cookie中设置的auth_headers用于确定请求是否经过身份validation,如果不是,则拒绝连接。

 module ApplicationCable class Connection < ActionCable::Connection::Base identified_by :current_user def connect self.current_user = find_verified_user end protected def find_verified_user # this checks whether a user is authenticated with devise_token_auth # parse cookies for values necessary for authentication auth_headers = JSON.parse(cookies['auth_headers']) uid_name = DeviseTokenAuth.headers_names[:'uid'] access_token_name = DeviseTokenAuth.headers_names[:'access-token'] client_name = DeviseTokenAuth.headers_names[:'client'] uid = auth_headers[uid_name] token = auth_headers[access_token_name] client_id = auth_headers[client_name] user = User.find_by_uid(uid) if user && user.valid_token?(token, client_id) user else reject_unauthorized_connection end end end end