ruby-on-rails 如何将devise_token_auth与ActionCable一起用于验证用户?

tyg4sfes  于 2023-01-03  发布在  Ruby
关注(0)|答案(3)|浏览(169)

我有一个带有devise_token_auth gem身份验证的Rails 5 API。
现在我想为经过身份验证的用户进行个人聊天。我没有资产,因为我正在使用API和前端是在本机应用程序中,我想要本机应用程序消息传递。
那么,我如何使用devise_token_auth gem对用户进行身份验证,以使用action cable进行个人消息传递呢

nvbavucw

nvbavucw1#

No cookies are generally supported in Rails 5 API. See: http://guides.rubyonrails.org/api_app.html#creating-a-new-application .
如果您首先在站点的某个地方进行普通HTTP身份验证(使用devise_token_auth gem),那么您会得到3个auth头-access_tokenclientuid
In such case you can use the Basic authentification for your Websockets connection (according https://devcenter.heroku.com/articles/websocket-security#authentication-authorization ) using these 3 auth headers:
调用(我使用Chrome Simple WebSocket Client):

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身份验证https://rubytutorial.io/actioncable-devise-authentication/
这样的身份验证可能已经足够了。我相信没有必要额外对频道订阅和发送到服务器的每个Websocket消息进行身份验证:
http://guides.rubyonrails.org/action_cable_overview.html#server-side-components-connections
对于服务器接受的每个WebSocket,都会示例化一个连接对象。该对象 * 成为从该对象创建的所有频道订阅的父对象 *。连接本身不处理除验证和授权之外的任何特定应用程序逻辑。
因此,如果您的连接是identified_by :current_user,您以后可以访问FooChannel < ApplicationCable::Channel中的任何位置!示例:

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中使用cookie,你可以打开它:
http://guides.rubyonrails.org/api_app.html#other-middleware

    • 配置/应用程序. rb**
config.middleware.use ActionDispatch::Cookies

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

    • 控制器/应用程序接口/应用程序控制器. rb**
class Api::ApplicationController < ActionController::API

    include ActionController::Cookies
...
zwghvu4y

zwghvu4y2#

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

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
b1uwtaje

b1uwtaje3#

我是这样做的,因为我们的React Native应用在头中发送身份验证:

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
        access_token = request.headers['access-token']
        uid          = request.headers['uid']
        client       = request.headers['client']

        user = User.find_by_uid(uid)

        if user && user.valid_token?(access_token, client)
          logger.add_tags 'ActionCable', uid

          user
        else
          reject_unauthorized_connection
        end
      end
  end
end

相关问题