【问题标题】:How to return Doorkeeper access token as json如何将门卫访问令牌返回为 json
【发布时间】:2014-06-13 13:27:07
【问题描述】:

我正在尝试为 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) 仍然没有返回它。

有谁知道如何以 json 格式返回 AccessToken,包括访问令牌本身?

【问题讨论】:

    标签: ruby-on-rails json devise doorkeeper


    【解决方案1】:

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

    # 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
    

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

    【讨论】:

      【解决方案2】:

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

      例如

      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
      

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

      【讨论】:

        【解决方案3】:

        我知道这个问题已经解决了一段时间。我最近想在我的 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"
            }
        }
        

        【讨论】:

          【解决方案4】:

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

          doorkeeper_token.token
          

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

          【讨论】:

            【解决方案5】:

            简单!您不需要从 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
            

            【讨论】:

              猜你喜欢
              • 2012-07-19
              • 2022-10-22
              • 2013-02-16
              • 1970-01-01
              • 2015-01-13
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多