我正在尝试为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?
返回答案 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