使用 Ruby on Rails 和 Devise 实现魔法链接
密码对用户来说是个问题。一个好的做法是通过电子邮件发送一个账户访问链接,该链接包含一个令牌,我们将使用该令牌来验证用户身份,最终让用户登录到他们的账户。接下来,我将向您展示一个使用 Devise 的 Ruby on Rails 6 实现示例。
注意:为了避免出错,我将从零开始创建一个应用程序。
设置
创建项目:$ rails new magicLinks -T --skip-turbokinks --database=postgresql
正在安装依赖项……
将此添加到您的Gemfile.rb
gem 'devise', '~> 4.7', '>= 4.7.1'
group :development, :test do
gem 'letter_opener', '~> 1.7' // For open emails in the browser
end
然后,$ bundle install
我们来安装 Devise:$ rails g devise:install && rails g devise User && rails db:create && rails db:migrate
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
config.action_mailer.delivery_method = :letter_opener
Devise 需要根路径,我们来添加:$ rails g controller welcome index。
将此添加到您的app/config/routes.rb:
root 'welcome#index'
开始吧👊
首先,我们需要在数据库中创建一个表来保存生成的令牌。
所以,$ rails g model EmailLink token expires_at:datetime user:references && rails db:migrate
现在我们将生成令牌,并在发生这种情况时发送电子邮件,为此,请在以下位置app/models/email_link.rb:
class EmailLink < ApplicationRecord
belongs_to :user
after_create :send_mail
def self.generate(email)
user = User.find_by(email: email)
return nil if !user
create(user: user, expires_at: Date.today + 1.day, token: generate_token)
end
def self.generate_token
Devise.friendly_token.first(16)
end
private
def send_mail
EmailLinkMailer.sign_in_mail(self).deliver_now
end
end
让我们生成控制器,以便在用户提供电子邮件地址并提交表单时触发之前的回调函数rails g controller EmailLinks new create。
让我们在代码中添加必要的路由app/config/routes.rb。
root 'welcome#index'
get 'email_links/new', as: :new_magic_link
post 'email_links/create', as: :magic_link
get 'email_links/validate', as: :email_link
现在,让我们为控制器添加功能:
class EmailLinksController < ApplicationController
def new
end
def create
@email_link = EmailLink.generate(params[:email])
if @email_link
flash[:notice] = "Email sent! Please, check your inbox."
redirect_to root_path
else
flash[:alert] = "There was an error, please try again!"
redirect_to new_magic_link_path
end
end
def validate
email_link = EmailLink.where(token: params[:token]).where("expires_at > ?", DateTime.now).first
unless email_link
flash[:alert] = "Invalid or expired token!"
redirect_to new_magic_link_path
end
sign_in(email_link.user, scope: :user)
redirect_to root_path
end
end
至此,我们的程序已经能够生成令牌、验证令牌并完成登录。剩下的工作就是发送电子邮件以及显示用户输入邮箱地址的页面。
注意:如果您想查看这些提示,必须将它们添加到app/views/layouts/application.html.erbbody 标签内:
<p class="notice"><%= notice %></p>
<p class="alert"><%= alert %></p>
发送电子邮件
很简单,首先我们要生成邮件程序,$ rails g mailer EmailLinkMailer然后赋予它相应的功能:
class EmailLinkMailer < ApplicationMailer
def sign_in_mail(email_link)
@token = email_link.token
@user = email_link.user
mail to: @user.email, subject: "Here is your magic link! 🚀"
end
end
让我们app/views/email_link_mailer/sign_in_mail.html.erb稍微修改一下邮件内容():
<p>Hello, <%= @user.email %>!</p>
<p>Recently someone requested a link to enter your account, if it was you, just press the button below to log in</p>
<%= link_to "Sign in to my account", email_link_url(token: @token) %>
太棒了!目前我们的程序已经能够发送电子邮件了,我们只需要一个主界面,用户可以在主界面上输入他们的电子邮件地址,然后我们就可以启动所有后端程序了。
只需添加以下简单表单app/views/email_links/new.html.erb:
<%= form_with(url: magic_link_path, method: :post) do %>
<%= label_tag :email, "E-mail address" %>
<%= email_field_tag :email, nil, placeholder:"carpintinimatias@gmail.com", autofocus: true, required: true %>
<%= submit_tag "Send!" %>
<% end %>
为了验证这种方法是否有效,我们可以添加以下示例app/views/welcome/index.html.erb:
<% if user_signed_in? %>
<p>Hello, <%= current_user.email %></p>
<%= link_to "Sign out", destroy_user_session_path, method: :delete %>
<% else %>
<p>Hey, Sign In with Magic Links!</p>
<%= link_to "Click here", new_magic_link_path %>
<% end %>
好了,就到这里。谢谢阅读。👋
文章来源:https://dev.to/matiascarpintini/magic-links-with-ruby-on-rails-and-devise-4e3o