RoR Devise:使用用户名或电子邮件登录

时间:2010-06-08 12:20:47

标签: ruby-on-rails authentication devise

让用户使用他们的电子邮件地址或用户名登录的最佳方法是什么?我正在使用warden + devise进行身份验证。我认为这可能不会太难,但我想我需要一些建议,在哪里放置所需的所有东西。也许设计已经提供了这个功能?就像在config / initializers / devise.rb中一样,你会写:

config.authentication_keys = [ :email, :username ]

要求用户名和电子邮件都可以登录。但我真的想只为用户名和电子邮件设置一个字段,并且只需要其中一个字段。我只是想象一下使用某些ASCII艺术,它应该在视图中看起来像这样:

Username or Email:
[____________________]

Password:
[____________________]

[Sign In]

11 个答案:

答案 0 :(得分:46)

我找到了解决问题的方法。我对它不太满意(我宁愿在初始化程序中指定它),但它现在有效。在用户模型中,我添加了以下方法:

def self.find_for_database_authentication(conditions={})
  find_by(username: conditions[:email]) || find_by(email: conditions[:email])
end

正如@sguha和@Chetan指出的那样,another great resource is available on the official devise wiki

答案 1 :(得分:25)

答案 2 :(得分:9)

def self.find_for_authentication(conditions)
  conditions = ["username = ? or email = ?", conditions[authentication_keys.first], conditions[authentication_keys.first]]
  # raise StandardError, conditions.inspect
  super
end

Use their example!

答案 3 :(得分:7)

确保您已添加用户名字段并将用户名添加到attr_accessible。 在用户

中创建登录虚拟属性

1)将登录名添加为attr_accessor

# Virtual attribute for authenticating by either username or email
# This is in addition to a real persisted field like 'username'
attr_accessor :login

2)添加登录attr_accessible

attr_accessible :login

告诉Devise使用:登录authentication_keys

修改config / initializers / devise.rb以获得:

config.authentication_keys = [ :login ]

在用户

中覆盖Devise的find_for_database_authentication方法
# Overrides the devise method find_for_authentication
# Allow users to Sign In using their username or email address
def self.find_for_authentication(conditions)
  login = conditions.delete(:login)
  where(conditions).where(["username = :value OR email = :value", { :value => login }]).first
end

更新您的观点 确保您在项目中拥有Devise视图,以便自定义它们

remove <%= f.label :email %>
remove <%= f.email_field :email %>
add <%= f.label :login %>   
add <%= f.text_field :login %>

答案 4 :(得分:2)

https://gist.github.com/867932:一切解决方案。登录,忘记密码,确认,解锁说明。

答案 5 :(得分:2)

Platforma Tec(设计作者)已经向他们的github wiki发布了一个解决方案,该解决方案使用基础Warden身份验证策略而不是插入Controller:

https://github.com/plataformatec/devise/wiki/How-To:-Allow-users-to-sign-in-using-their-username-or-email-address

(之前的答案有一个断开的链接,我相信这个链接可以链接到这个资源。)

答案 6 :(得分:1)

如果您使用 MongoDB (使用MongoId),则需要进行不同的查询:

  def self.find_for_database_authentication(conditions={})
    self.any_of({name: conditions[:email]},{email: conditions[:email]}).limit(1).first
  end

就这样它会在某个地方上线。

答案 7 :(得分:1)

使用 squeel gem,您可以执行以下操作:

  def self.find_for_authentication(conditions={})
    self.where{(email == conditions[:email]) | (username == conditions[:email])}.first
  end

答案 8 :(得分:1)

这是一个Rails解决方案,它重构了@ padde的答案。它使用ActiveRecord的find_by来简化调用,确保只有一个基于正则表达式的调用,并且如果你想允许它,也支持数字ID(对于脚本/ API很有用)。电子邮件的正则表达式就像它需要在这种情况下一样简单;只是检查是否存在@,因为我认为你的用户名验证员不允许@字符。

def self.find_for_database_authentication(conditions={})
  email = conditions[:email]
  if email =~ /@/ 
    self.find_by_email(email)
  elsif email.to_s =~ /\A[0-9]+\z/
    self.find(Integer(email))
  else
    self.find_by_username(email])
  end
end

与wiki和@ aku的答案一样,我还建议使用attr_accessible和authentication_keys而不是使用:email here来创建一个新的:login参数。 (我将其保留为:示例中的电子邮件以显示快速修复。)

答案 9 :(得分:1)

我写得像这样,它就可以了。不知道这是不是“丑陋的修复”,但如果我想出一个更好的解决方案,我会告诉你......

 def self.authenticate(email, password)
   user = find_by_email(email) ||
     username = find_by_username(email)
   if user && user.password_hash = BCrypt::Engine.hash_secret(password, user.password_salt)
     user
   else
     nil
   end
end

答案 10 :(得分:1)

我使用快速入侵,以避免更改任何特定设计代码并将其用于我的特定场景(我特别将其用于移动应用可以在服务器上创建用户的API)。

我已经向所有设计控制器添加了一个before_filter,如果传递了用户名,我会从用户名生成一封电子邮件(“#{params [:user] [:username]} @ mycustomdomain.com”并保存用户。对于所有其他调用,我基于相同的逻辑生成电子邮件。我的before_filter看起来像这样:

def generate_email_for_username
    return if(!params[:user][:email].blank? || params[:user][:username].blank?)
    params[:user][:email] = "#{params[:user][:username]}@mycustomdomain.com"
end

我也在用户表中保存用户名,因此我知道以@ mycustomdomain.com结尾的电子邮件用户是使用用户名创建的。