为什么此登录表单失败且没有错误?

问题描述

TL;DR 为什么我的用户登录表单没有创建新会话/为什么它失败而没有错误

我对 Rails 还很陌生,我对创建新会话的用户登录表单有些困惑。本质上,我可以在不创建会话的情况下登录用户,或者登录不起作用并且也不创建会话,但我没有收到任何错误

我试过了:

  1. 使用我能找到的任何版本的 form_with,以及 form_forform_tag
  2. 更改我在谷歌中可以找到的任何东西的路线。
  3. 设置 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' %>