Skip to content

Commit

Permalink
Merge pull request #175 from graphql-devise/allow-controller-level-au…
Browse files Browse the repository at this point in the history
…thentication

Allow controller level authentication
  • Loading branch information
mcelicalderon committed May 8, 2021
2 parents 23b14e5 + 2155f5d commit 3d4972c
Show file tree
Hide file tree
Showing 22 changed files with 213 additions and 109 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# frozen_string_literal: true

module GraphqlDevise
module Concerns
module AdditionalControllerMethods
extend ActiveSupport::Concern

included do
attr_accessor :client_id, :token, :resource
end

def gql_devise_context(models)
{
current_resource: authenticate_model(models),
controller: self
}
end

def authenticate_model(models)
Array(models).each do |model|
set_resource_by_token(model)
return @resource if @resource.present?
end

nil
end

def resource_class(resource = nil)
# Return the resource class instead of looking for a Devise mapping if resource is already a resource class
return resource if resource.respond_to?(:find_by)

super
end

def full_url_without_params
request.base_url + request.path
end

def set_resource_by_token(resource)
set_user_by_token(resource)
end

def graphql_context(resource_name)
{
resource_name: resource_name,
controller: self
}
end

def build_redirect_headers(access_token, client, redirect_header_options = {})
{
DeviseTokenAuth.headers_names[:"access-token"] => access_token,
DeviseTokenAuth.headers_names[:client] => client,
:config => params[:config],
:client_id => client,
:token => access_token
}.merge(redirect_header_options)
end
end
end
end
32 changes: 5 additions & 27 deletions app/controllers/graphql_devise/concerns/set_user_by_token.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,12 @@

module GraphqlDevise
module Concerns
SetUserByToken = DeviseTokenAuth::Concerns::SetUserByToken
module SetUserByToken
extend ActiveSupport::Concern

SetUserByToken.module_eval do
attr_accessor :client_id, :token, :resource

def full_url_without_params
request.base_url + request.path
end

def set_resource_by_token(resource)
set_user_by_token(resource)
end

def graphql_context(resource_name)
{
resource_name: resource_name,
controller: self
}
end

def build_redirect_headers(access_token, client, redirect_header_options = {})
{
DeviseTokenAuth.headers_names[:"access-token"] => access_token,
DeviseTokenAuth.headers_names[:client] => client,
:config => params[:config],
:client_id => client,
:token => access_token
}.merge(redirect_header_options)
included do
include DeviseTokenAuth::Concerns::SetUserByToken
include GraphqlDevise::Concerns::AdditionalControllerMethods
end
end
end
Expand Down
4 changes: 2 additions & 2 deletions app/helpers/graphql_devise/mailer_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
module GraphqlDevise
module MailerHelper
def confirmation_query(resource_name:, token:, redirect_url:)
name = "#{resource_name.underscore.tr('/', '_').camelize(:lower)}ConfirmAccount"
name = "#{GraphqlDevise.to_mapping_name(resource_name).camelize(:lower)}ConfirmAccount"
raw = <<-GRAPHQL
query($token:String!,$redirectUrl:String!){
#{name}(confirmationToken:$token,redirectUrl:$redirectUrl){
Expand All @@ -19,7 +19,7 @@ def confirmation_query(resource_name:, token:, redirect_url:)
end

def password_reset_query(token:, redirect_url:, resource_name:)
name = "#{resource_name.underscore.tr('/', '_').camelize(:lower)}CheckPasswordToken"
name = "#{GraphqlDevise.to_mapping_name(resource_name).camelize(:lower)}CheckPasswordToken"
raw = <<-GRAPHQL
query($token:String!,$redirectUrl:String!){
#{name}(resetPasswordToken:$token,redirectUrl:$redirectUrl){
Expand Down
21 changes: 21 additions & 0 deletions app/models/graphql_devise/concerns/additional_model_methods.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# frozen_string_literal: true

require 'graphql_devise/model/with_email_updater'

module GraphqlDevise
module Concerns
module AdditionalModelMethods
extend ActiveSupport::Concern

class_methods do
def reconfirmable
devise_modules.include?(:confirmable) && column_names.include?('unconfirmed_email')
end
end

def update_with_email(attributes = {})
GraphqlDevise::Model::WithEmailUpdater.new(self, attributes).call
end
end
end
end
15 changes: 6 additions & 9 deletions app/models/graphql_devise/concerns/model.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,14 @@

module GraphqlDevise
module Concerns
Model = DeviseTokenAuth::Concerns::User
module Model
extend ActiveSupport::Concern

Model.module_eval do
class_methods do
def reconfirmable
devise_modules.include?(:confirmable) && column_names.include?('unconfirmed_email')
end
end
included do
include DeviseTokenAuth::Concerns::User
include GraphqlDevise::Concerns::AdditionalModelMethods

def update_with_email(attributes = {})
GraphqlDevise::Model::WithEmailUpdater.new(self, attributes).call
GraphqlDevise.configure_warden_serializer_for_model(self)
end
end
end
Expand Down
24 changes: 19 additions & 5 deletions lib/graphql_devise.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,36 @@ def self.load_schema
@schema_loaded = true
end

def self.resource_mounted?(mapping_name)
@mounted_resources.include?(mapping_name)
def self.resource_mounted?(model)
@mounted_resources.include?(model)
end

def self.mount_resource(mapping_name)
@mounted_resources << mapping_name
def self.mount_resource(model)
@mounted_resources << model
end

def self.add_mapping(mapping_name, resource)
return if Devise.mappings.key?(mapping_name)
return if Devise.mappings.key?(mapping_name.to_sym)

Devise.add_mapping(
mapping_name.to_s.pluralize.to_sym,
module: :devise, class_name: resource
)
end

def self.to_mapping_name(resource)
resource.to_s.underscore.tr('/', '_')
end

def self.configure_warden_serializer_for_model(model)
Devise.warden_config.serialize_into_session(to_mapping_name(model)) do |record|
model.serialize_into_session(record)
end

Devise.warden_config.serialize_from_session(to_mapping_name(model)) do |args|
model.serialize_from_session(*args)
end
end
end

require 'graphql_devise/engine'
Expand Down
6 changes: 3 additions & 3 deletions lib/graphql_devise/concerns/controller_methods.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,11 @@ def controller
end

def resource_name
self.class.instance_variable_get(:@resource_name)
GraphqlDevise.to_mapping_name(resource_class)
end

def resource_class
controller.send(:resource_class, resource_name)
self.class.instance_variable_get(:@resource_klass)
end

def recoverable_enabled?
Expand All @@ -60,7 +60,7 @@ def blacklisted_redirect_url?(redirect_url)
end

def current_resource
@current_resource ||= controller.send(:set_user_by_token, resource_name)
@current_resource ||= controller.send(:set_resource_by_token, resource_class)
end

def client
Expand Down
12 changes: 6 additions & 6 deletions lib/graphql_devise/mount_method/operation_preparer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@
require_relative 'operation_preparers/gql_name_setter'
require_relative 'operation_preparers/mutation_field_setter'
require_relative 'operation_preparers/resolver_type_setter'
require_relative 'operation_preparers/resource_name_setter'
require_relative 'operation_preparers/resource_klass_setter'
require_relative 'operation_preparers/default_operation_preparer'
require_relative 'operation_preparers/custom_operation_preparer'

module GraphqlDevise
module MountMethod
class OperationPreparer
def initialize(mapping_name:, selected_operations:, preparer:, custom:, additional_operations:)
def initialize(model:, selected_operations:, preparer:, custom:, additional_operations:)
@selected_operations = selected_operations
@preparer = preparer
@mapping_name = mapping_name
@model = model
@custom = custom
@additional_operations = additional_operations
end
Expand All @@ -22,18 +22,18 @@ def call
default_operations = OperationPreparers::DefaultOperationPreparer.new(
selected_operations: @selected_operations,
custom_keys: @custom.keys,
mapping_name: @mapping_name,
model: @model,
preparer: @preparer
).call

custom_operations = OperationPreparers::CustomOperationPreparer.new(
selected_keys: @selected_operations.keys,
custom_operations: @custom,
mapping_name: @mapping_name
model: @model
).call

additional_operations = @additional_operations.each_with_object({}) do |(action, operation), result|
result[action] = OperationPreparers::ResourceNameSetter.new(@mapping_name).call(operation)
result[action] = OperationPreparers::ResourceKlassSetter.new(@model).call(operation)
end

default_operations.merge(custom_operations).merge(additional_operations)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,21 @@ module GraphqlDevise
module MountMethod
module OperationPreparers
class CustomOperationPreparer
def initialize(selected_keys:, custom_operations:, mapping_name:)
def initialize(selected_keys:, custom_operations:, model:)
@selected_keys = selected_keys
@custom_operations = custom_operations
@mapping_name = mapping_name
@model = model
end

def call
mapping_name = GraphqlDevise.to_mapping_name(@model)

@custom_operations.slice(*@selected_keys).each_with_object({}) do |(action, operation), result|
mapped_action = "#{@mapping_name}_#{action}"
mapped_action = "#{mapping_name}_#{action}"

result[mapped_action.to_sym] = [
OperationPreparers::GqlNameSetter.new(mapped_action),
OperationPreparers::ResourceNameSetter.new(@mapping_name)
OperationPreparers::ResourceKlassSetter.new(@model)
].reduce(operation) { |prepared_operation, preparer| preparer.call(prepared_operation) }
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,25 @@ module GraphqlDevise
module MountMethod
module OperationPreparers
class DefaultOperationPreparer
def initialize(selected_operations:, custom_keys:, mapping_name:, preparer:)
def initialize(selected_operations:, custom_keys:, model:, preparer:)
@selected_operations = selected_operations
@custom_keys = custom_keys
@mapping_name = mapping_name
@model = model
@preparer = preparer
end

def call
mapping_name = GraphqlDevise.to_mapping_name(@model)

@selected_operations.except(*@custom_keys).each_with_object({}) do |(action, operation_info), result|
mapped_action = "#{@mapping_name}_#{action}"
mapped_action = "#{mapping_name}_#{action}"
operation = operation_info[:klass]
options = operation_info.except(:klass)

result[mapped_action.to_sym] = [
OperationPreparers::GqlNameSetter.new(mapped_action),
@preparer,
OperationPreparers::ResourceNameSetter.new(@mapping_name)
OperationPreparers::ResourceKlassSetter.new(@model)
].reduce(child_class(operation)) do |prepared_operation, preparer|
preparer.call(prepared_operation, **options)
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
module GraphqlDevise
module MountMethod
module OperationPreparers
class ResourceNameSetter
def initialize(name)
@name = name
class ResourceKlassSetter
def initialize(klass)
@klass = klass
end

def call(operation, **)
operation.instance_variable_set(:@resource_name, @name)
operation.instance_variable_set(:@resource_klass, @klass)

operation
end
Expand Down
Loading

0 comments on commit 3d4972c

Please sign in to comment.