使用 Ruby on Rails 5 API 进行基于令牌的身份验证
介绍
随着仅使用 API 的应用程序如此流行,并且 Rails 5 即将推出,最常见的身份验证方法现在都基于令牌。在本指南中,我将简要概述基于令牌的身份验证以及如何将其实现到 Rails 5 仅使用 API 的应用程序中。
什么是基于令牌的身份验证?
基于令牌的身份验证(也称为JSON Web Token 身份验证)是处理应用程序中用户身份验证的一种新方法。它是基于会话的身份验证的替代方案。
基于会话的身份验证和基于令牌的身份验证之间最显著的区别在于,基于会话的身份验证严重依赖于服务器。为每个登录用户创建一条记录。
基于令牌的身份验证是无状态的 - 它不会在服务器上存储任何内容,但会创建一个唯一的编码令牌,每次发出请求时都会进行检查。
与基于会话的身份验证不同,令牌方法不会将用户与登录信息关联,而是与用于进行客户端主机事务的唯一令牌关联。许多应用程序(包括 Facebook、Google 和 GitHub)都使用基于令牌的方法。
基于令牌的身份验证的好处
使用这种方法有几个好处:
跨域/CORS
Cookies 和 CORS 不能很好地跨不同域混合使用。基于令牌的方法允许您对任何域上的任何服务器进行 AJAX 调用,因为您使用 HTTP 标头来传输用户信息。
无国籍
令牌是无状态的。无需保留会话存储,因为令牌是一个独立的实体,其中存储了所有用户信息。
解耦
您不再受特定身份验证方案的约束。令牌可以在任何地方生成,因此可以使用单个经过身份验证的命令从任何地方调用 API,而不必进行多次经过身份验证的调用。
移动就绪
在原生移动应用中存储用户信息时,Cookie 是一个问题。采用基于令牌的方法可大大简化此保存过程。
CSRF(跨站请求伪造)
由于应用程序不依赖 cookie 进行身份验证,因此它不容易受到跨站点请求攻击。
表现
就服务器端负载而言,网络往返(例如在数据库中查找会话)可能比计算 HMACSHA256 代码以验证令牌并解析其内容花费更多时间。这使得基于令牌的身份验证比传统替代方案更快。
基于令牌的身份验证如何工作?
The way token-based authentication works is simple. The user enters his or her credentials and sends a request to the server. If the credentials are correct, the server creates a unique HMACSHA256 encoded token, also known as JSON web token (JWT). The client stores the JWT and makes all subsequent requests to the server with the token attached. The server authenticates the user by comparing the JWT sent with the request to the one it has stored in the database. Here is a simple diagram of the process:
What Does a JWT Token Contain?
The token is separated into three base-64 encoded, dot-separated values. Each value represents a different type of data:
Header
Consists of the type of the token (JWT) and the type of encryption algorithm (HS256) encoded in base-64.
Payload
The payload contains information about the user and his or her role. For example, the payload of the token can contain the e-mail and the password.
Signature
Signature is a unique key that identifies the service which creates the header. In this case, the signature of the token will be a base-64 encoded version of the Rails application's secret key (Rails.application.secrets.secret_key_base). Because each application has a unique base key, this secret key serves as the token signature.
Setting up a Token-based Authentication with Rails 5
Enough theory, it's time for practice. The first step is to create a new Rails 5 API-only application:
rails _5.0.0.beta3_ new api-app --api
By appending --api at the end of the generator, an API-only application will be created. API-only applications are recent additions to the Rails platform. An API application is a trimmed-down version of standard Rails application without any of the unnecessary middleware, such as .erb views, helpers, and assets. API applications come with special middlewares such as ActionController::API, request throttling, easy CORS configuration and other custom-waived features for building APIs.
There are several requirements that need to be met before we can use the token-based approach:
- We need an accessible model.
- A way of encoding and decoding JWT tokens must be implemented.
- We need methods for checking if the user is authenticated.
- Controllers for creating and logging in users are also necessary.
- We need routes for creating users and logging them in and out.
Creating the User Model
First, the user model must be created:
rails g model User name email password_digest
Run the migrations:
rails db:migrate
By running these methods, we create a user model with name, e-mail, and password fields and have its schema migrated in the database.
The method has_secure_password must be added to the model to make sure the password is properly encrypted into the database: has_secure_password is part of the bcrypt gem, so we have to install it first. Add it to the gemfile:
#Gemfile.rb
gem 'bcrypt', '~> 3.1.7'
And install it:
bundle install
安装 gem 后,可以将该方法包含在模型中:
#app/models/user.rb
class User < ApplicationRecord
has_secure_password
end
编码和解码 JWT 令牌
一旦用户模型完成,就可以开始实现 JWT 令牌生成。首先,jwt gem 将使 Rails 应用程序中提供 HMACSHA256 令牌的编码和解码。首先:
gem 'jwt'
然后安装它:
bundle install
一旦安装了 gem,就可以通过JWT全局变量来访问它。由于要使用的方法需要封装,因此单例类是包装逻辑并在其他构造中使用它的好方法。
对于那些不熟悉的人来说,单例类将类的实例化限制为单个对象,当只需要一个对象来完成手头的任务时,这非常方便。
# lib/json_web_token.rb
class JsonWebToken
class << self
def encode(payload, exp = 24.hours.from_now)
payload[:exp] = exp.to_i
JWT.encode(payload, Rails.application.secrets.secret_key_base)
end
def decode(token)
body = JWT.decode(token, Rails.application.secrets.secret_key_base)[0]
HashWithIndifferentAccess.new body
rescue
nil
end
end
end
第一个方法encode需要三个参数——用户 ID、到期时间(1 天)和 Rails 应用程序的唯一基本密钥——来创建一个唯一的令牌。
第二种方法,解码,获取令牌并使用应用程序的密钥对其进行解码。
以下是使用这些方法的两种情况:
- 用于对用户进行身份验证并使用编码为其生成令牌。
- 使用解码来检查每个请求中附加的用户令牌是否正确。
为了确保一切正常运行,Rails 应用程序加载时必须包含lib目录的内容。
#config/application.rb
module ApiApp
class Application < Rails::Application
#.....
config.autoload_paths << Rails.root.join('lib')
#.....
end
end
验证用户
除了使用私有控制器方法外,还可以使用simple_command。有关安装的更多信息,请参阅文章simple_command。
简单命令 gem 是创建服务的简单方法。它的作用类似于助手的作用,但它促进了控制器和模型之间的连接,而不是控制器和视图之间的连接。这样,我们可以缩短模型和控制器中的代码。
将 gem 添加到你的Gemfile中:
gem 'simple_command'
并将其捆绑:
bundle install
然后,通过编写prepend SimpleCommand,可以在类中轻松使用simple_command的别名方法。命令的结构如下:
class AuthenticateUser
prepend SimpleCommand
def initialize()
#this is where parameters are taken when the command is called
end
def call
免责声明:本内容来源于第三方作者授权、网友推荐或互联网整理,旨在为广大用户提供学习与参考之用。所有文本和图片版权归原创网站或作者本人所有,其观点并不代表本站立场。如有任何版权侵犯或转载不当之情况,请与我们取得联系,我们将尽快进行相关处理与修改。感谢您的理解与支持!
请先 登录后发表评论 ~