Rails API 全能认证
Rails API Omniauth
我正在尝试使用 NuxtJS 框架在 Rails API 中使用 Devise 实现 Omniauth。
我使用 Omniauth 方法进行了身份验证模块连接和用户帐户创建,但我想了解如何重定向用户 signin/signup,我是 Rails 开发人员和 NuxtJS 初学者。
后端
用户模型oauth注册方法:
def self.from_facebook(auth)
where(uid: auth.uid, provider: auth.provider).first_or_create do |user|
user.email = auth.info.email
user.first_name = auth.info.first_name
user.last_name = auth.info.last_name
user.password = Devise.friendly_token[0, 20]
user.provider = auth.provider
user.uid = auth.uid
Client.create(user: user)
end
end
注册控制器:
# frozen_string_literal: true
module Overrides
class RegistrationsController < DeviseTokenAuth::ApplicationController
before_action :set_user_by_token, only: [:destroy, :update]
before_action :validate_sign_up_params, only: :create
before_action :validate_account_update_params, only: :update
skip_after_action :update_auth_header, only: [:create, :destroy]
def create
build_resource
unless @resource.present?
raise DeviseTokenAuth::Errors::NoResourceDefinedError,
"#{self.class.name} #build_resource does not define @resource,"\
' execution stopped.'
end
# give redirect value from params priority
@redirect_url = params.fetch(
:confirm_success_url,
DeviseTokenAuth.default_confirm_success_url
)
# success redirect url is required
if confirmable_enabled? && !@redirect_url
return render_create_error_missing_confirm_success_url
end
# if whitelist is set, validate redirect_url against whitelist
return render_create_error_redirect_url_not_allowed if blacklisted_redirect_url?
# override email confirmation, must be sent manually from ctrl
resource_class.set_callback('create', :after, :send_on_create_confirmation_instructions)
resource_class.skip_callback('create', :after, :send_on_create_confirmation_instructions)
if @resource.respond_to? :skip_confirmation_notification!
# Fix duplicate e-mails by disabling Devise confirmation e-mail
@resource.skip_confirmation_notification!
end
if @resource.save
if params[:farmer]
Farmer.create(
user: @resource
)
else
Client.create(
user: @resource
)
end
yield @resource if block_given?
unless @resource.confirmed?
# user will require email authentication
@resource.send_confirmation_instructions({
client_config: params[:config_name],
redirect_url: @redirect_url
})
end
if active_for_authentication?
# email auth has been bypassed, authenticate user
@client_id, @token = @resource.create_token
@resource.save!
update_auth_header
end
render_create_success
else
clean_up_passwords @resource
render_create_error
end
end
def update
if @resource
if @resource.send(resource_update_method, account_update_params)
yield @resource if block_given?
render_update_success
else
render_update_error
end
else
render_update_error_user_not_found
end
end
def destroy
if @resource
@resource.destroy
yield @resource if block_given?
render_destroy_success
else
render_destroy_error
end
end
def sign_up_params
params.permit(
:first_name,
:last_name,
:email,
:cellphone,
:phone,
:password,
:password_confirmation,
:birthdate
)
end
def account_update_params
params.permit(*params_for_resource(:account_update))
end
protected
def build_resource
@resource = resource_class.new(sign_up_params)
@resource.provider = provider
# honor devise configuration for case_insensitive_keys
if resource_class.case_insensitive_keys.include?(:email)
@resource.email = sign_up_params[:email].try(:downcase)
else
@resource.email = sign_up_params[:email]
end
end
def render_create_error_missing_confirm_success_url
response = {
status: 'error',
data: resource_data
}
message = I18n.t('devise_token_auth.registrations.missing_confirm_success_url')
render_error(422, message, response)
end
def render_create_error_redirect_url_not_allowed
response = {
status: 'error',
data: resource_data
}
message = I18n.t('devise_token_auth.registrations.redirect_url_not_allowed', redirect_url: @redirect_url)
render_error(422, message, response)
end
def render_create_success
render json: {
status: 'success',
data: resource_data
}
end
def render_create_error
render json: {
status: 'error',
data: resource_data,
errors: resource_errors
}, status: 422
end
def render_update_success
render json: {
status: 'success',
data: resource_data
}
end
def render_update_error
render json: {
status: 'error',
errors: resource_errors
}, status: 422
end
def render_update_error_user_not_found
render_error(404, I18n.t('devise_token_auth.registrations.user_not_found'), status: 'error')
end
def render_destroy_success
render json: {
status: 'success',
message: I18n.t('devise_token_auth.registrations.account_with_uid_destroyed', uid: @resource.uid)
}
end
def render_destroy_error
render_error(404, I18n.t('devise_token_auth.registrations.account_to_destroy_not_found'), status: 'error')
end
private
def resource_update_method
if DeviseTokenAuth.check_current_password_before_update == :attributes
'update_with_password'
elsif DeviseTokenAuth.check_current_password_before_update == :password && account_update_params.key?(:password)
'update_with_password'
elsif account_update_params.key?(:current_password)
'update_with_password'
else
'update_attributes'
end
end
def validate_sign_up_params
validate_post_data sign_up_params, I18n.t('errors.messages.validate_sign_up_params')
end
def validate_account_update_params
validate_post_data account_update_params, I18n.t('errors.messages.validate_account_update_params')
end
def validate_post_data which, message
render_error(:unprocessable_entity, message, status: 'error') if which.empty?
end
def active_for_authentication?
!@resource.respond_to?(:active_for_authentication?) || @resource.active_for_authentication?
end
end
end
Omniauth 回调控制器:
def facebook
@user = User.from_facebook(request.env["omniauth.auth"])
# NOTE: redirection here
end
前端
策略:
facebook: {
client_id: 'CLIENT_ID',
userinfo_endpoint: 'https://graph.facebook.com/v2.12/me?fields=about,name,picture{url},email,birthday',
redirect_uri:'http://localhost:3000/omniauth/facebook',
scope: ['public_profile', 'email', 'user_birthday']
}
登录方式:
facebookLogin () {
this.$auth.loginWith('facebook')
.then((response) => {
this.$toast.success({
title: 'Connexion réussie',
message: 'Vous vous êtes bien connecté.',
position: 'bottom center',
timeOut: 3000
})
})
.catch(() => {
this.$toast.error({
title: 'Erreur',
message: 'L\'email ou le mot de passe ne sont pas valides. Vérifiez votre saisie.',
position: 'bottom center',
timeOut: 8000
})
})
.finally(() => this.$wait.end('signing in'))
}
几件事...
- Omniauth 回调控制器缺少重定向信息(这就是那个注释存在的原因吗?)。如果您使用的是 Devise,它应该在
@user = ...
行下方显示类似 sign_in_and_redirect @user
的内容。
- Devise 带有内置路由。要使用它们,您必须在 routes.rb 文件中包含类似
devise for :users
的内容。查看 this page 上的“Devise_for magic”部分,查看这些内置路由的示例。请注意,您必须配置一些 Devise 模型才能工作。
- 运行
rake routes
查看您定义的路由是否符合您的预期。
- 如果你想不通,我还使用 Omniauth 和设计创建了一个项目。你可以查看我的代码here.
我正在尝试使用 NuxtJS 框架在 Rails API 中使用 Devise 实现 Omniauth。
我使用 Omniauth 方法进行了身份验证模块连接和用户帐户创建,但我想了解如何重定向用户 signin/signup,我是 Rails 开发人员和 NuxtJS 初学者。
后端
用户模型oauth注册方法:
def self.from_facebook(auth)
where(uid: auth.uid, provider: auth.provider).first_or_create do |user|
user.email = auth.info.email
user.first_name = auth.info.first_name
user.last_name = auth.info.last_name
user.password = Devise.friendly_token[0, 20]
user.provider = auth.provider
user.uid = auth.uid
Client.create(user: user)
end
end
注册控制器:
# frozen_string_literal: true
module Overrides
class RegistrationsController < DeviseTokenAuth::ApplicationController
before_action :set_user_by_token, only: [:destroy, :update]
before_action :validate_sign_up_params, only: :create
before_action :validate_account_update_params, only: :update
skip_after_action :update_auth_header, only: [:create, :destroy]
def create
build_resource
unless @resource.present?
raise DeviseTokenAuth::Errors::NoResourceDefinedError,
"#{self.class.name} #build_resource does not define @resource,"\
' execution stopped.'
end
# give redirect value from params priority
@redirect_url = params.fetch(
:confirm_success_url,
DeviseTokenAuth.default_confirm_success_url
)
# success redirect url is required
if confirmable_enabled? && !@redirect_url
return render_create_error_missing_confirm_success_url
end
# if whitelist is set, validate redirect_url against whitelist
return render_create_error_redirect_url_not_allowed if blacklisted_redirect_url?
# override email confirmation, must be sent manually from ctrl
resource_class.set_callback('create', :after, :send_on_create_confirmation_instructions)
resource_class.skip_callback('create', :after, :send_on_create_confirmation_instructions)
if @resource.respond_to? :skip_confirmation_notification!
# Fix duplicate e-mails by disabling Devise confirmation e-mail
@resource.skip_confirmation_notification!
end
if @resource.save
if params[:farmer]
Farmer.create(
user: @resource
)
else
Client.create(
user: @resource
)
end
yield @resource if block_given?
unless @resource.confirmed?
# user will require email authentication
@resource.send_confirmation_instructions({
client_config: params[:config_name],
redirect_url: @redirect_url
})
end
if active_for_authentication?
# email auth has been bypassed, authenticate user
@client_id, @token = @resource.create_token
@resource.save!
update_auth_header
end
render_create_success
else
clean_up_passwords @resource
render_create_error
end
end
def update
if @resource
if @resource.send(resource_update_method, account_update_params)
yield @resource if block_given?
render_update_success
else
render_update_error
end
else
render_update_error_user_not_found
end
end
def destroy
if @resource
@resource.destroy
yield @resource if block_given?
render_destroy_success
else
render_destroy_error
end
end
def sign_up_params
params.permit(
:first_name,
:last_name,
:email,
:cellphone,
:phone,
:password,
:password_confirmation,
:birthdate
)
end
def account_update_params
params.permit(*params_for_resource(:account_update))
end
protected
def build_resource
@resource = resource_class.new(sign_up_params)
@resource.provider = provider
# honor devise configuration for case_insensitive_keys
if resource_class.case_insensitive_keys.include?(:email)
@resource.email = sign_up_params[:email].try(:downcase)
else
@resource.email = sign_up_params[:email]
end
end
def render_create_error_missing_confirm_success_url
response = {
status: 'error',
data: resource_data
}
message = I18n.t('devise_token_auth.registrations.missing_confirm_success_url')
render_error(422, message, response)
end
def render_create_error_redirect_url_not_allowed
response = {
status: 'error',
data: resource_data
}
message = I18n.t('devise_token_auth.registrations.redirect_url_not_allowed', redirect_url: @redirect_url)
render_error(422, message, response)
end
def render_create_success
render json: {
status: 'success',
data: resource_data
}
end
def render_create_error
render json: {
status: 'error',
data: resource_data,
errors: resource_errors
}, status: 422
end
def render_update_success
render json: {
status: 'success',
data: resource_data
}
end
def render_update_error
render json: {
status: 'error',
errors: resource_errors
}, status: 422
end
def render_update_error_user_not_found
render_error(404, I18n.t('devise_token_auth.registrations.user_not_found'), status: 'error')
end
def render_destroy_success
render json: {
status: 'success',
message: I18n.t('devise_token_auth.registrations.account_with_uid_destroyed', uid: @resource.uid)
}
end
def render_destroy_error
render_error(404, I18n.t('devise_token_auth.registrations.account_to_destroy_not_found'), status: 'error')
end
private
def resource_update_method
if DeviseTokenAuth.check_current_password_before_update == :attributes
'update_with_password'
elsif DeviseTokenAuth.check_current_password_before_update == :password && account_update_params.key?(:password)
'update_with_password'
elsif account_update_params.key?(:current_password)
'update_with_password'
else
'update_attributes'
end
end
def validate_sign_up_params
validate_post_data sign_up_params, I18n.t('errors.messages.validate_sign_up_params')
end
def validate_account_update_params
validate_post_data account_update_params, I18n.t('errors.messages.validate_account_update_params')
end
def validate_post_data which, message
render_error(:unprocessable_entity, message, status: 'error') if which.empty?
end
def active_for_authentication?
!@resource.respond_to?(:active_for_authentication?) || @resource.active_for_authentication?
end
end
end
Omniauth 回调控制器:
def facebook
@user = User.from_facebook(request.env["omniauth.auth"])
# NOTE: redirection here
end
前端
策略:
facebook: {
client_id: 'CLIENT_ID',
userinfo_endpoint: 'https://graph.facebook.com/v2.12/me?fields=about,name,picture{url},email,birthday',
redirect_uri:'http://localhost:3000/omniauth/facebook',
scope: ['public_profile', 'email', 'user_birthday']
}
登录方式:
facebookLogin () {
this.$auth.loginWith('facebook')
.then((response) => {
this.$toast.success({
title: 'Connexion réussie',
message: 'Vous vous êtes bien connecté.',
position: 'bottom center',
timeOut: 3000
})
})
.catch(() => {
this.$toast.error({
title: 'Erreur',
message: 'L\'email ou le mot de passe ne sont pas valides. Vérifiez votre saisie.',
position: 'bottom center',
timeOut: 8000
})
})
.finally(() => this.$wait.end('signing in'))
}
几件事...
- Omniauth 回调控制器缺少重定向信息(这就是那个注释存在的原因吗?)。如果您使用的是 Devise,它应该在
@user = ...
行下方显示类似sign_in_and_redirect @user
的内容。 - Devise 带有内置路由。要使用它们,您必须在 routes.rb 文件中包含类似
devise for :users
的内容。查看 this page 上的“Devise_for magic”部分,查看这些内置路由的示例。请注意,您必须配置一些 Devise 模型才能工作。 - 运行
rake routes
查看您定义的路由是否符合您的预期。 - 如果你想不通,我还使用 Omniauth 和设计创建了一个项目。你可以查看我的代码here.