更新
我进一步澄清了我在本帖末尾列出的问题。
我正在尝试通过包含令牌身份验证的电子邮件URL在Devise中实现懒惰(又称软注册)注册。在我的网站上,User
has_many :payments
和Payment
belongs_to :user
。当User
创建新Payment
时,它包含属性:email
,该属性代表新的非注册用户(我将其称为“访客”)。我使用ActionMailer向这位新访客发送电子邮件。
在这封发送的电子邮件中,我希望包含一个带有令牌身份验证的URL(例如http://localhost/index?auth_token=TOKENVALUE
),以便访客可以查看和编辑需要身份验证的视图,并专门为他们自定义(基于他们的:email
)。访客还应该能够注册为User
- 因为我已经拥有他们的电子邮件地址,他们只需要提供密码。
Payment
模型进行更改/app/models/payment.rb
class Payment < ActiveRecord::Base
attr_accessible :amount, :description, :email, :frequency, :paid, :user_id
belongs_to :user
validates :email, :presence => true, :format => { :with => /.+@.+\..+/i }
validates :amount, :presence => true
validates :description, :presence => true
end
/app/models/user.rb
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :confirmable
# I will also need to add ":token_authenticatable"
attr_accessible :email, :password, :password_confirmation, :remember_me
has_many :payments
end
User
表与创建的新Payments
保持同步,以便:email
表中创建的任何新Payment
自动添加到User
表格为:email
?User
应包含令牌但不包含密码,因为用户尚未注册该站点。我应该使用空白密码,随机生成的字符串或其他来创建新的User
吗?在任何一种情况下,我认为他们需要从他们的令牌认证URL进入注册页面,以防止其他人在他们的电子邮件用户名下注册(例如懒惰注册)如果可能,我的偏好是使用Devise,因为我使用了许多功能。我是RoR的新手,感谢您提出的任何建议!
编辑:以下是我用于解决上述问题#1的代码,在我的付款控制器中,以防其他人有用
def create
@payment = current_user.payments.build(params[:payment])
#Here is the code I added to keep User :email in sync with Payment :email, without token authentication implemented yet
unless User.find_by_email(params[:payment][:email].downcase)
u = User.new({:email => params[:payment][:email].downcase, :password => nil, :password_confirmation => nil })
u.skip_confirmation!
u.save(:validate => false) #skip validation
end
respond_to do |format|
if @payment.save
format.html { redirect_to payments_url, :flash => { notice: 'Payment was successfully created.' } }
format.json { render json: @payment, status: :created, location: @payment }
else
format.html { render action: "new" }
format.json { render json: @payment.errors, status: :unprocessable_entity }
end
end
end
答案 0 :(得分:2)
当你知道如何很好地使用它们以及你想要做的事情符合框架的设计时,像Devise这样的框架是很棒的。当你开始尝试“弯曲”他们做他们不打算做的事情时,或许他们试图在不完全理解他们如何在内部工作的情况下修补它们,根据我的经验,你只是弄得一团糟。我去过那儿。通常你会被简化为“黑客直到它工作”......这实际上意味着“黑客攻击直到看起来有效,除了十几个微妙的错误,只会在以后出现”。
在这样的情况下,我倾向于“滚动我自己的”登录和身份验证代码,也许会查看Devise源代码以获取创意。
(事实上,我今天在新的Rails应用程序上做到了这一点......花了几个小时的时间,现在一次又一次地检查Devise源代码,编写我的项目实际需要的200行代码。相比之下,设计自己有大约2500行。)
您询问了有关代码“整体策略和结构”的想法。如果您决定实施自己的自定义登录/身份验证代码,它可能会是这样的:
session
哈希中,以确定用户是否已登录,以及访客/用户。确保您的会话存储在数据库中,而不是存储在cookie中。ApplicationController
(或混合到Module
的{{1}})以封装对此登录信息的访问权。ApplicationController
,如果用户未登录则会重定向。对于密码存储/验证,请使用before_filter
gem。在您的用户模型上,您需要一个bcrypt-ruby
字符串字段,可能还需要一些方法:
password_hash
对于基于令牌的身份验证,请将require 'bcrypt'
def password
# BCrypt handles generation and storage of salts
@password ||= ::BCrypt::Password.new(password_hash)
end
def password=(password)
@password = ::BCrypt::Password.create(password)
self.password_hash = @password
end
def authenticate_by_password(password)
self.password == password
end
字符串字段添加到您的用户模型(或Guest或其他任何内容......)。使它成为一个独特的领域。您可以使用类似的东西生成唯一的令牌(从Devise借来并稍微修改一下):
login_token
然后当用户点击您设置require 'securerandom'
def generate_login_token
loop do
token = SecureRandom.base64(15).tr('+/=lIO0', 'pqrsxyz')
unless User.where(:login_token => token).exists?
self.login_token = token
self.save!
return
end
end
end
的{{1}}操作时,请执行以下操作:
login
确保在params[:token]
字段上放置数据库索引。
还有别的吗?