如何将门卫访问令牌作为json返回

时间:2014-06-13 13:27:07

标签: ruby-on-rails json devise doorkeeper

我正在尝试为iOS应用程序创建一个登录系统,其中后端由设备和门卫提供。

我想限制网络请求的数量,因此不希望必须从凭据中获取令牌,然后将用户详细信息作为单独的请求获取。

这是我目前的尝试:

token = Doorkeeper::AccessToken.create!(application_id: @application_id,
    resource_owner_id: current_user.id, :expires_in => 168.hours)
puts token.token
render :json => {:user => current_user, :token => token.as_json(:include=> token)}, 
    status: :ok, location: :users

但是返回的是:

{"user":{"id":2,"email":"user3@test.com","created_at":"2014-06-12T17:25:12.000Z",
"updated_at":"2014-06-13T12:20:18.536Z",
"firstName":"user","lastName":"test","subscription":null},
"token":{"resource_owner_id":2,"scopes":[],"expires_in_seconds":604800,
"application":{"uid":"[Filtered]"}}}

因此,实际的access_token密钥不会被传回以允许我进行将来的呼叫。 我可以看到令牌本身并未在DoorKeeper::AccessToken.as_json中返回,但token.as_json(:include=> token)仍然无法返回。

有没有人知道如何将AccessToken(包括访问令牌本身)作为json?

返回

5 个答案:

答案 0 :(得分:5)

我处理这个问题的方法是创建一个自定义令牌控制器并覆盖令牌请求操作。在那里,我可以附加自定义内容来回应。

# app/controllers/custom_tokens_controller.rb
class CustomTokensController < Doorkeeper::TokensController

  # Overriding create action
  # POST /oauth/token
  def create
    response = strategy.authorize
    body = response.body

    if response.status == :ok
      # User the resource_owner_id from token to identify the user
      user = User.find(response.token.resource_owner_id) rescue nil

      unless user.nil?
        ### If you want to render user with template
        ### create an ActionController to render out the user
        # ac = ActionController::Base.new()
        # user_json = ac.render_to_string( template: 'api/users/me', locals: { user: user})
        # body[:user] = Oj.load(user_json)

        ### Or if you want to just append user using 'as_json'
        body[:user] = user.as_json
      end
    end

    self.headers.merge! response.headers
    self.response_body = body.to_json
    self.status        = response.status

  rescue Doorkeeper::Errors::DoorkeeperError => e
    handle_token_exception e
  end
end

请确保您在routes.rb

中指向此控制器
# routes.rb
Rails.application.routes.draw do

  # Doorkeeper
  use_doorkeeper do
    controllers :tokens => 'custom_tokens'
  end

  # Your other routes here...

end

这是经过测试的,它可以使用,我在我的项目中使用它。

答案 1 :(得分:2)

我设法解决这个问题的方法是创建我自己的AccessToken类,它重载as_json方法以包含我想要的字段。

e.g

class AccessToken < Doorkeeper::AccessToken
   def as_json(options={})
      {
        :token => self.token,
        #:resource_owner_id => self.resource_owner_id,
        #:scopes => self.scopes,
        :created_at => self.created_at,
        :expires_in_seconds => self.expires_in_seconds,
        #:application => { :uid => self.application.uid }
      }
   end
end

如果有人有更好的解决方案我会全力以赴

答案 2 :(得分:1)

我知道它已经解决了一段时间了。我最近想在我的API上实现相同的行为,我依靠模型关联来实现它:

class User < ActiveRecord::Base
  has_one :token, -> { order 'created_at DESC' }, class: Doorkeeper::AccessToken, foreign_key: :resource_owner_id
end

然后使用序列化器:

class UserSerializer < ActiveModel::Serializer
  attributes :id, :name, :email
  has_one :token, serializer: AccessTokenSerializer
end

class AccessTokenSerializer < ActiveModel::Serializer
  attributes :token, :expires_in_seconds
end

您只需将数据返回为:

class DummyController < ApplicationController
  def dummy
    respond_with current_user, status: :ok
  end
end

将输出如下所示的JSON:

{
    "id": 17,
    "name": "Chuck Norris",
    "email": "chuck@norr.is",
    "token": {
        "token": "c62af258f2d1ac816f65606a2a8413b8e0c2ad5b4434f9c75b56765f54ee627b",
        "expires_in_seconds": "5427"
    }
}

答案 3 :(得分:0)

实际上我们可以通过以下方式获取访问令牌:

doorkeeper_token.token

您可以将其包含在json响应中,这样您就不需要在门卫本身内编辑任何内容。
但是,在将它包含在json响应中之前不要忘记添加一些条件,因为在响应中总是显示它似乎不太好。

答案 4 :(得分:0)

容易!您无需继承Doorkeeper::TokensController,但如果更适合您的情况,则可以:

class CustomController < ApplicationController
  def create
    ...
    access_token = Doorkeeper::AccessToken.create!(application_id: @application_id, resource_owner_id: current_user.id, :expires_in => 168.hours)
    render json: Doorkeeper::OAuth::TokenResponse.new(access_token).body
  end
end