devise_token_auth 指南:Rails API 中的简单身份验证
实施步骤
实际使用情况
我想为我的 Rails API 创建一个身份验证系统,但 API(没有客户端)的一个问题是无法使用会话或 Cookie 进行身份验证。
因此,我使用了 gem devise_token_auth
,它使用令牌。简单来说,它的工作原理是:当您发出 HTTP 请求进行注册或登录时,响应标头会为您提供身份验证令牌,您需要在后续 HTTP 请求的标头中发送该令牌,以证明您已通过身份验证。
虽然官方文档提供了大部分你需要的信息,但我发现有几个地方比较困惑,所以我把这篇文章留着以后参考。希望对你有帮助!
注意:指南适用于 Linux 或 MacOS。
实施步骤
还请随意查看我创建的骨架存储库,作为如何使用这个 gem 的概念证明。
1. 安装 devise_token_auth
将以下内容添加到您的Gemfile
,然后bundle
从命令行运行:
gem 'devise_token_auth'
2.生成必要的文件
从命令行执行此操作。
rails g devise_token_auth:install User auth
这将做很多事情,包括:
- 创建一个
User
模型,存储用户邮箱地址等信息,以及相应的迁移文件 - 在您的文件中添加一行,
config/routes.rb
指定身份验证端点(如注册或登录)的路由(如果您希望将其路由到其他地方,请将命令中的/auth/
“ ”替换为其他内容)auth
有关此命令的详尽列表,请查看文档。
更新
根据 Rafael 在下面的评论,现在需要添加extend Devise::Models
到此处生成的模型文件中。详细信息可在此 Github问题User
中找到。
3. 迁移数据库
在命令行中运行rails db:migrate
以应用在步骤#2中创建的迁移文件,该文件可能看起来像db/migrate/YYYYMMDDTTTT_devise_token_auth_create_users.rb
。
4. 配置初始化文件
转到您的config/initializers/devise_token_auth.rb
文件(也是rails g
在步骤#2中的命令中创建的)。
再次,文档中有您可以进行的完整配置列表,但举一个例子:
config.change_headers_on_each_request = false
默认情况下,授权标头会随着每个请求而变化。这意味着您每次请求都会收到新的令牌,并且每次都必须返回不同的令牌。我希望能够继续使用相同的令牌,因此我将其设置为 来关闭false
。
重复使用令牌并非最佳安全做法,因此在生产环境中每次使用新令牌可能更好。
5. 禁用 JSON 请求的伪造保护
Rails 控制器预设了针对跨站请求伪造 (CSRF) 攻击的措施。这需要将渲染后的 HTML 中的令牌与 Rails 自动存储在会话中的令牌进行比较。但对于 API,我们没有会话,而是使用我们自己的令牌,因此无需进行此类操作(详情请见此处)。
重要的是要记住 XML 或 JSON 请求也会受到影响,如果您正在构建 API,则应该更改 ApplicationController 中的伪造保护方法(默认情况下::exception)
因此,请继续并禁用 JSON 格式请求的伪造检查app/controllers/application_controller.rb
。
注意:仅当所有请求都通过 API 传入时才执行此操作。
class ApplicationController < ActionController::Base
protect_from_forgery unless: -> { request.format.json? }
end
注意事项
- 跳过此步骤将导致此错误:
ActionController::InvalidAuthenticityToken in DeviseTokenAuth::RegistrationsController#create
。 - 如果您
ApplicationController
继承自ActionController::API
(如果您使用标志初始化项目,则应该是这种情况--api
),则此步骤应该是不必要的,因为默认情况下没有伪造保护。
6. 尝试注册用户
现在,让我们尝试注册一个测试用户。使用 命令行启动你的 Rails 服务器rails s
,并向localhost:3000/auth/
(或你的自定义路由)发送一个 HTTP POST 请求,参数如下。
{
"email": "test@email.com",
"password": "password",
"password_confirmation": "password"
}
它应该返回状态 200 - 成功。现在你的身份验证系统可以正常工作了!
7. 向控制器添加身份验证
接下来,在相应的控制器文件中添加一行代码,使身份验证成为必要。例如,假设我们正在为存储书籍信息的数据库构建一个 API。我们有一个books_controller.rb
用于从数据库中添加或删除书籍的文件。我们希望在用户添加或删除条目之前对其进行身份验证。
class BooksController < ApiController
before_action :authenticate_user!
# Code for methods such as create and delete should come here.
end
现在,无论何时您向图书控制器中的任何方法发送 HTTP 请求,除非您已通过身份验证,否则都会返回错误。
实际使用情况
我之前提到过,注册用户的 HTTP 请求是向 发出的 POST 请求localhost:3000/auth/
。至于完整的方法列表(例如,登录/注销用户以及更改密码),请参阅文档。您可以看到所需的请求类型、路由和参数。
最后,我们来谈谈实际使用方法。具体步骤如下:
- 发送身份验证请求(注册或登录)
- 返回状态 200,标头中包含有效的身份验证令牌
- 在您的下一个请求中,将这些令牌发送到您的标头中
所需的令牌类别包括:
- 访问令牌
- 客户
- uid
就这么简单!
我还想讨论一下测试的技巧,但由于篇幅太长,我会另开一篇文章来写。谢谢阅读 :)
更新
这是有关测试的文章!
附加更新
该模块似乎已从基于的gemtrackable
中删除。因此,模型中的默认配置(包含)可能会引发如下错误:。 有关如何解决此问题的详细信息,请参阅以下链接:devise
devise_token_auth
User
:trackable
NoMethodError: undefined method 'current_sign_in_at'
- https://stackoverflow.com/questions/55735895/nomethoderror-undefined-method-current-sign-in-at-for-user0x000055ce01dcf0a
- https://www.bountysource.com/issues/75245078-cant-log-in-nomethoderror-undefined-method-current_sign_in_at-for-user-0x000055e053c79c58
你好!
很棒的帖子,只需在 devise_token_auth 安装后添加以下语句:“extends Devise::Models”来开始用户模型即可。这适用于 Rails 6 版本。
其他的都可以 :)