diff --git a/app/controllers/api/application_controller.rb b/app/controllers/api/application_controller.rb index 3010f1b..7bccbc5 100644 --- a/app/controllers/api/application_controller.rb +++ b/app/controllers/api/application_controller.rb @@ -3,4 +3,26 @@ class Api::ApplicationController < ApplicationController before_action :login_required skip_before_action :verify_authenticity_token + + private + + def current_user + session[:user_id] = User.find_by(email: param_email).id if session[:user_id].blank? && valid_token_request? + super + end + + def valid_token_request? + return false unless param_email.present? && param_token.present? + + token = OneTimeToken.valid.find_by(token: param_token) + return token.try(:user).try(:email) == param_email + end + + def param_email + request.headers["x-nasulog-auth-user"] || params["auth_user"] + end + + def param_token + request.headers["x-nasulog-auth-token"] || params["auth_token"] + end end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb index 377187b..4660cc7 100644 --- a/app/controllers/api/users_controller.rb +++ b/app/controllers/api/users_controller.rb @@ -4,6 +4,10 @@ class Api::UsersController < Api::ApplicationController def show end + def auth_token + render nothing: true, status: 401 and return if current_user.blank? + @token = current_user.create_one_time_token + end private diff --git a/app/models/one_time_token.rb b/app/models/one_time_token.rb new file mode 100644 index 0000000..02c299b --- /dev/null +++ b/app/models/one_time_token.rb @@ -0,0 +1,35 @@ +# == Schema Information +# +# Table name: one_time_tokens +# +# id :integer not null, primary key +# user_id :integer not null +# token :string(128) +# expires_at :datetime not null +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# index_one_time_tokens_on_token (token) +# index_one_time_tokens_on_user_id (user_id) +# + +class OneTimeToken < ApplicationRecord + belongs_to :user + before_validation :set_token, :set_expires_at + + scope :valid, -> { + where('expires_at > ?', Time.current) + } + + private + + def set_token + self.token ||= SecureRandom.hex(64) + end + + def set_expires_at + self.expires_at ||= (Time.current + 5.minutes) + end +end diff --git a/app/models/user.rb b/app/models/user.rb index 15b7a5b..bd25402 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -14,6 +14,7 @@ class User < ApplicationRecord has_many :read_poems, dependent: :destroy has_many :poems, dependent: :destroy + has_one :one_time_token, dependent: :destroy def my_poem?(poem) self == poem.user @@ -23,6 +24,11 @@ def my_read_poem?(read_poem) self == read_poem.user end + def create_one_time_token + OneTimeToken.delete_all(user_id:id) + one_time_token = OneTimeToken.create(user_id: id) + end + def self.form_omniauth(auth) User.create( google_uid: auth[:uid], diff --git a/app/views/api/users/auth_token.json.jbuilder b/app/views/api/users/auth_token.json.jbuilder new file mode 100644 index 0000000..c712efe --- /dev/null +++ b/app/views/api/users/auth_token.json.jbuilder @@ -0,0 +1,5 @@ +json.auth_token do + json.user @token.user.email + json.token @token.token + json.expires_at @token.expires_at.to_i +end diff --git a/config/routes.rb b/config/routes.rb index aaa7e75..bd4356e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -27,6 +27,7 @@ scope module: :user do resources 'poems', only: [:index], defaults: { format: :json } end + get :auth_token, defaults: { format: :json } end end end diff --git a/db/migrate/20160411044136_create_one_time_tokens.rb b/db/migrate/20160411044136_create_one_time_tokens.rb new file mode 100644 index 0000000..811cec9 --- /dev/null +++ b/db/migrate/20160411044136_create_one_time_tokens.rb @@ -0,0 +1,12 @@ +class CreateOneTimeTokens < ActiveRecord::Migration[5.0] + def change + create_table :one_time_tokens do |t| + t.references :user, null:false + t.string :token, limit: 128 + t.datetime :expires_at, null: false + t.timestamps null: false + end + + add_index :one_time_tokens, :token + end +end diff --git a/db/schema.rb b/db/schema.rb index 46e07a7..f6dac08 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,17 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20160123054054) do +ActiveRecord::Schema.define(version: 20160411044136) do + + create_table "one_time_tokens", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4" do |t| + t.integer "user_id", null: false + t.string "token", limit: 128 + t.datetime "expires_at", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["token"], name: "index_one_time_tokens_on_token", using: :btree + t.index ["user_id"], name: "index_one_time_tokens_on_user_id", using: :btree + end create_table "poems", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4" do |t| t.integer "user_id" diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb new file mode 100644 index 0000000..361c036 --- /dev/null +++ b/spec/requests/api/users_spec.rb @@ -0,0 +1,33 @@ +require 'rails_helper' + +RSpec.describe "Api::Users", type: :request do + let(:current_user) { nil } + + before(:each) do + allow_any_instance_of(Api::ApplicationController).to receive(:current_user).and_return current_user + allow_any_instance_of(Api::ApplicationController).to receive(:login_required).and_return true + end + + describe 'GET /api/user/auth_token' do + subject { get auth_token_api_user_path } + + context '非ログイン' do + it "トークンの取得はできない" do + subject + expect(response).to have_http_status(401) + end + end + + context 'ログイン済み' do + let (:current_user) { create(:user) } + + it "トークンが取得可能" do + subject + expect(response).to have_http_status(200) + end + + #TODO 取得したトークンでログインできるか、も見たい・・・ + end + end + +end