#ruby-on-rails #devise
#ruby-on-rails #разработка
Вопрос:
Я использую rails 4.1.2 и devise 3.2.4
Я видел, как этот вопрос задавался ранее, и просматривал Интернет в поисках решения, но все рекомендации не работают. После успешного входа (для участника увеличен sign_in_count, метод current_member возвращает правильный участник), разработайте маршруты обратно на исходную страницу, которую участник пытался просмотреть, но
Completed 401 Unauthorized in 2ms
результат всегда есть, и участник перенаправляется обратно на страницу входа (сеансы #новые)
В моем макете есть мета-теги CSRF.
Я попытался определить маршруты, которые я хочу аутентифицировать:
devise_for :members, :path => '/' # i want sign in path to be /sign_in
devise_scope: :members do
root 'application#index'
get 'car_wash/:dealer_id', to: 'car_wash#show'
post 'car_wash/:id/update', to: 'car_wash#update'
end
В контроллерах я хочу пройти аутентификацию:
before_filter :authenticate_member!
В модели участников
devise :database_authenticatable, :authenticatable, :rememberable, :trackable, :authentication_keys => [ :username ]
Журнал выглядит следующим образом:
12:26:34 web.1 | Started POST "/sign_in" for 127.0.0.1 at 2014-07-02 12:26:34 -0500
12:26:34 web.1 | Processing by Members::SessionsController#create as HTML
12:26:34 web.1 | Parameters: {"utf8"=>"✓","authenticity_token"=>"4tQIel82ktomEwfsvkgXzB7XfXJlmJxmlea9BnjaIYk=", "member"=>{"username"=>"John", "password"=>"[FILTERED]", "remember_me"=>"0"}, "commit"=>"Sign in"}
12:26:34 web.1 | Member Load (0.5ms) SELECT "members".* FROM "members" WHERE "members"."username" = 'John' LIMIT 1
12:26:35 web.1 | (0.3ms) BEGIN
12:26:35 web.1 | (0.3ms) COMMIT
12:26:35 web.1 | (0.2ms) BEGIN
12:26:35 web.1 | SQL (0.5ms) UPDATE "members" SET "current_sign_in_at" = $1, "last_sign_in_at" = $2, "sign_in_count" = $3, "updated_at" = $4 WHERE "members"."id" = 1 [["current_sign_in_at", "2014-07-02 17:26:35.878880"], ["last_sign_in_at", "2014-07-02 17:23:42.608524"], ["sign_in_count", 23], ["updated_at", "2014-07-02 17:26:35.879614"]]
12:26:35 web.1 | (6.3ms) COMMIT
12:26:35 web.1 | Redirected to http://localhost:3000/
12:26:35 web.1 | Completed 302 Found in 1408ms (ActiveRecord: 8.6ms)
12:26:35 web.1 |
12:26:35 web.1 |
12:26:35 web.1 | Started GET "/" for 127.0.0.1 at 2014-07-02 12:26:35 -0500
12:26:35 web.1 | Processing by ApplicationController#index as HTML
12:26:35 web.1 | Completed 401 Unauthorized in 2ms
12:26:35 web.1 |
12:26:35 web.1 |
12:26:35 web.1 | Started GET "/sign_in" for 127.0.0.1 at 2014-07-02 12:26:35 -0500
12:26:35 web.1 | Processing by Members::SessionsController#new as HTML
12:26:35 web.1 | Rendered devise/shared/_links.erb (0.1ms)
12:26:35 web.1 | Rendered devise/sessions/new.html.erb within layouts/application (4.2ms)
12:26:35 web.1 | Rendered shared/_header.html.haml (1.5ms)
12:26:35 web.1 | Completed 200 OK in 24ms (Views: 21.2ms | ActiveRecord: 1.0ms)
Я использую пользовательскую стратегию warden для определения успеха или неудачи аутентификации на основе вызова внешнего API. Я прошел через каждую часть этой логики, и она отлично работает!
# config/initializers/devise.rb
config.warden do |manager|
manager.intercept_401 = false
manager.default_strategies(:scope => :member).unshift :member_login
end
Но по какой-то причине успешный вход не зависает.
РЕДАКТИРОВАТЬ: найдено решение. Проблема заключалась в моей пользовательской стратегии аутентификации Warden (большой сюрприз):
Warden::Strategies.add(:member_login) do
def member_params
ActionController::Parameters.new(@response).permit(:first_name, :last_name, :role, :username, :external_api_user_id)
end
def valid?
params[:member] amp;amp; ( params[:member][:username] || params[:member][:password] )
end
def authenticate!
member = Member.find_by_username(params[:member][:username])
if authenticate_with_ppd_api
if member
member.update(member_params)
success!(member)
else
member = Member.create(member_params)
success!(member)
end
else
fail!("Incorrect username or password")
end
end
def authenticate_with_api
@response = HTTParty.post('https://path.to.server/admin/login', body: { username: params[:member][:username], password: params[:member][:password] } )
@response = JSON.parse(@response.body).first
@response["authenticated"]
end
end
Я не разрешал ‘authenticity_token’ для участника. После добавления этого, вход работает:
ActionController::Parameters.new(@response).permit(:authenticity_token, :first_name, :last_name, :role, :username, :external_api_user_id)
Это все еще очень сбивает меня с толку. Я только обновлял / создавал пользователя для своих собственных целей, а не для чего-либо, связанного с аутентификацией. Я понятия не имею, почему обновление токена подлинности не происходит автоматически. Это могло бы помочь, если бы я знал, что делает стратегия Warden по умолчанию. Ну что ж. По крайней мере, это работает.
РЕДАКТИРОВАТЬ: О боже! Что ж, вход работает, но выход — нет! Это «исправление» делает возможным вход в систему, но не выход. Отправка запроса на УДАЛЕНИЕ в /sign_out абсолютно ничего не дает. Вернуться к исходной точке 1