使用Rails&Devise为移动设备建立一个简单的API登陆服务
使用的工具与源代码
Devise (https://github.com/plataformatec/devise)
Rails 4 (https://github.com/rails/rails)
Ruby-china 源代码 (https://github.com/ruby-china/ruby-china)
流程
利用API进行登陆,获取授权代码信息,使用授权代码信息与需要进行验证的API进行交互
配置Devise
增加authentication_token字段
假如应用已经初始化过了devise的user表,那么就需要额外利用rails生成一个新的数据迁移脚本
#rails g migration addAuthTokenToUser
class AddAuthTokenToUser < ActiveRecord::Migration
def change
change_table :users do |t|
t.string :authentication_token
end
add_index :users, :authentication_token, :unique => true
end
end
编辑models/user.rb,增加相应的devise功能 :token_authenticatable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,:token_authenticatable
建立控制器与路由
我们需要建立一个名为Token的控制器作为登陆/获取授权代码的入口
则先配置相应的路由,在config/routes.rb文件中增加以下代码
#config/routes.rb
namespace :api do
namespace :v1 do
resources :tokens,:only => [:create, :destroy]
resources :products
end
end
然后新建相应的tokens_controller.rb文件,首先先写一个登陆登陆的方法
#controllers/api/v1/tokens_controller.rb
class Api::V1::TokensController < ApplicationController
skip_before_filter :verify_authenticity_token
respond_to :json
def create
email = params[:email]
password = params[:password]
if email.nil? or password.nil?
render :status=>400,:json=>{:message=>"Password&Username cannot be blank"}
return
end
@user=User.find_by_email(email.downcase)
@user=User.find_by_email(email.downcase)
if @user.nil?
render :status=>401, :json=>{:message=>"Invalid email or passoword."}
return
end
if not @user.valid_password?(password)
render :status=>401, :json=>{:message=>"Invalid email or password."}
else
render :status=>200, :json=> {:token=>@user.authentication_token}
end
end
end
这样相当于建立一个api路径-localhost:3000/api/v1/tokens.json,顺便说明跳过的这个前置验证器
skip_before_filter :verify_authenticity_token
因为rails默认会为所有Post的form增加一个提交表单用的验证代码,防止站外提交post方法。(《企业应用架构》一书里好似关于这种设计的具体说明)。但是通过手机提交post方法无法获取这段验证代码,所以api部分全部需要忽略这个内建的验证期。
测试
使用curl测试是不是正常工作
curl -XPOST -d '' localhost:3000/api/v1/tokens.json
因为没有输入用户名和密码应该返回一个我们设置的错误信息,{"message":"The request must contain the user email and password."}
如果输入正确的用和用户用户名如
curl -XPOST -d "email=test@gmail.com&password=123456" localhost:3000/api/v1/tokens.json
则会收到一个正确的应答,并且获取相应用户的authentication_token栏位的值,{"token":"aiSf8jGqyPACcY3Myjxj"}。
不使用Devise的验证方法
阅读了Devise的文档,不知道是不是我会错意了,好似如果使用devise内置的auth_token方案,则web部分也会受到波及,需要使用authenticate_user!方法的地方都会额外验证auth_token,还需要修改devise.rb增加配置。
这里使用ruby-china一段很简单的验证方法,
def current_user
token = params[:auth_token]
@current_user ||= User.where(:authentication_token => token).first
end
def authenticate!
render :status=>400,
:json=>{:message=>"Need login."} unless current_user
end
这里相当于重新实现了一个API专用的current_user 和 authenticate_user! 方法。相应的只需要在将来需要进行登陆验证的API中都加入auth_token=xxx的参数即可。
这里额外写一段需要炎验证的Controller代码进行演示:
class Api::V1::ListController.rb < ApplicationController
before_filter :authenticate! #验证token
respond_to :json
def index
@lists=List.all.limit(10)
render :status=>200, :json=> @lists
end
end
如果使用curl 进行测试,则额外的需要在get请求中写明auth_token的参数值,例如
localhost:3000/api/v1/lists.json?auth_token=xxx
结束语
这段代码只是演示如果利用Rails与Devise快速的建立一套需要验证的API体系。