问题描述
TL;DR 为什么我的用户登录表单没有创建新会话/为什么它失败而没有错误?
我对 Rails 还很陌生,我对创建新会话的用户登录表单有些困惑。本质上,我可以在不创建会话的情况下登录用户,或者登录不起作用并且也不创建会话,但我没有收到任何错误。
我试过了:
- 使用我能找到的任何版本的
form_with
,以及form_for
和form_tag
。 - 更改我在谷歌中可以找到的任何东西的路线。
- 设置
SameSite="Lax"
。
new.html.erb
<h1>This is the new viewer page!</h1>
<%= form_with model: @user do |f| %>
<%= f.label :name %>
<%= f.text_field :name %><br>
<%= f.label :username %>
<%= f.text_field :username %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :password %>
<%= f.text_field :password %>
<%= f.submit %>
<% end %>
<%= form_for :session,url: login_path do |f| %>
<%= f.label :id %>
<%= f.text_field :id %>
<%= f.submit "Sign in" %>
<% end %>
sessions_controller.rb
class SessionsController < ApplicationController
def new
end
def create
@user = User.find_by_id(params[:id])
if @user && @user.authenticate(params[:id][:password_digest])
session[:id] = @user.id
redirect_to user_path(@user),notice: "User logged in"
else
redirect_to root_path,alert: "Something is wrong"
end
end
def destroy
session[:user_id] = nil
redirect_to root_path
end
end
routes.rb
Rails.application.routes.draw do
# For details on the DSL available within this file,see https://guides.rubyonrails.org/routing.html
resources :users
resources :sessions
get "/login",to: "sessions#new"
post "/login",to: "sessions#create",via: :"post"
delete "/logout",to: "sessions#destroy"
root "users#new"
end
我知道我的 flash 消息对调试毫无用处,我也找不到任何关于获得更清晰的调试输出的简单方法。我唯一能找到的是浏览器控制台中关于 samesite=none 的警告,因此 cookie 将被拒绝(我正在使用 firefox)
编辑
我尝试提交表单时的日志
Started POST "/login" for 127.0.0.1 at 2021-01-22 01:01:56 -0500
Processing by SessionsController#create as HTML
Parameters: {"authenticity_token"=>"uUeDMYJKaxduZGqKJvadisO1bCFYDSIz6dcmp6CEeUNTYwBycJUb5l10K5KXcPZG2kOgdiK6pvPAKoDexwqSmA==","session"=>{"id"=>"12"},"commit"=>"Sign in"}
[1m[36mUser Load (0.4ms)[0m [1m[34mSELECT "users".* FROM "users" WHERE "users"."id" IS NULL LIMIT ?[0m [["LIMIT",1]]
↳ app/controllers/sessions_controller.rb:6:in `create'
Redirected to http://localhost:3000/
Completed 302 Found in 14ms (ActiveRecord: 0.4ms | Allocations: 1013)
Started GET "/" for 127.0.0.1 at 2021-01-22 01:01:56 -0500
Processing by UsersController#new as HTML
Rendering users/new.html.erb within layouts/application
Rendered users/new.html.erb within layouts/application (Duration: 2.3ms | Allocations: 1302)
[Webpacker] Everything's up-to-date. nothing to do
Completed 200 OK in 9ms (Views: 8.7ms | ActiveRecord: 0.0ms | Allocations: 4667)
编辑 2
进行一些更改后登录:
Started POST "/users" for 127.0.0.1 at 2021-01-23 03:22:03 -0500
Processing by UsersController#create as JS
Parameters: {"authenticity_token"=>"TIbECQO9vWQfDfmT89rGHKtdlamLXOUG3MYVgiB1bqZJJgp8C0h9LmFdyrLOS4HTmi/IHBp5bz0flz7BRU5wYA==","user"=>{"id"=>"12"},"commit"=>"Sign in"}
Redirected to http://localhost:3000/users/12
Completed 200 OK in 9ms (ActiveRecord: 0.0ms | Allocations: 2142)
Started GET "/users/12" for 127.0.0.1 at 2021-01-23 03:22:03 -0500
Processing by UsersController#show as HTML
Parameters: {"id"=>"12"}
[1m[36mUser Load (0.3ms)[0m [1m[34mSELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?[0m [["id",12],["LIMIT",1]]
↳ app/controllers/users_controller.rb:3:in `show'
Rendering users/show.html.erb within layouts/application
Rendered users/show.html.erb within layouts/application (Duration: 1.3ms | Allocations: 96)
[Webpacker] Everything's up-to-date. nothing to do
Completed 200 OK in 12ms (Views: 8.1ms | ActiveRecord: 0.3ms | Allocations: 4300)
解决方法
什么都没发生的原因是代码完全损坏了。
查看日志中的参数:
Processing by UsersController#create as JS
Parameters: {"authenticity_token"=>"TIbECQO9vWQfDfmT89rGHKtdlamLXOUG3MYVgiB1bqZJJgp8C0h9LmFdyrLOS4HTmi/IHBp5bz0flz7BRU5wYA==","user"=>{"id"=>"12"},"commit"=>"Sign in"}
现在看看你的 create 方法:
def create
@user = User.find_by_id(params[:id])
if @user && @user.authenticate(params[:id][:password_digest])
session[:id] = @user.id
redirect_to user_path(@user),notice: "User logged in"
else
redirect_to root_path,alert: "Something is wrong"
end
end
在参数中的任何地方都没有传递 params[:id]
或任何密码。 params[:id][:password_digest]
也总是为零。因此,如果 @user && @user.authenticate(params[:id][:password_digest])
永远不会为真。
params[:id][:password_digest]
是直接的疯子,因为您使用加密算法(如 bcrypt)从纯文本密码生成密码摘要并将其保存在数据库中。您实际上永远不会从用户那里获取密码摘要。
相反,当用户登录时,您使用纯文本密码并将其传递给 bcrypt,它会告诉您密码摘要是否与为该字符串生成的任何哈希匹配。如果是 .authenticate
则返回 true。
让用户提供和 id 而不是电子邮件或用户名之类的东西也很奇怪。
你真正想要的是:
class User < ApplicationRecord
has_secure_password
end
class SessionsController < ApplicationController
# GET /login
def new; end
# POST /login
def create
@user = User.find_by_email(params[:email])
if @user&.autenticate(params[:password])
session[:user_id] = @user.id
else
flash.now[:error] = 'Invalid email or password'
render :new
end
end
# DELETE /logout
def destroy
session.delete(:user_id)
redirect_to root_path
end
end
# app/views/sessions/_form.html.erb
# this creates a form with "unnested" inputs
<%= form_with url: login_path,local: true do |form| %>
<div class="field">
<%= f.label :email %>
<%= f.email_field :email %>
</div>
<div class="field">
<%= f.label :password %>
<%= f.password_field :email %>
</div>
<%= f.submit "Sign in" %>
<% end %>
# app/views/sessions/new.html.erb
<h1>Sign in</h1>
<%= render partial: 'form' %>