首页 > 解决方案 > 无法使用 JWT 身份验证在 Rails 后端创建用户对象

问题描述

我正在尝试使用 JWT 身份验证在 Rails PostgreSQL 数据库中创建用户对象。当我从我的 React 前端触发 create user 方法时,用户不是在后端创建的,我怀疑这与我的控制器的设置方式有关。

这是我的 Rails 后端中的用户控制器:

class Api::V1::UsersController < ApplicationController
  before_action :find_user, only: [:show]
  skip_before_action :authorized, only: [:index, :create]

  def index
    @users = User.all
    render json: @users
  end

  def show
    render json: @user
  end

  def create
    @user = User.create(user_params)
    if @user.valid?
      @token = encode_token(user_id: @user.id)
      render json: { user: UserSerializer.new(@user), jwt: @token }, status: :created
    else
      render json: {error: "Could not create user"}, status: :unprocessible_entity
    end
  end

end

private

def user_params
  params.permit(:username, :password)
end

def find_user
  @user = User.find(params[:id])
end

这是我的 JWT 的“身份验证”控制器:

class Api::V1::AuthController < ApplicationController
  skip_before_action :authorized, only: [:create]

  def create # POST /api/v1/login
    @user = User.find_by(username: user_login_params[:username])
    if @user && @user.authenticate(user_login_params[:password])
      @token = encode_token({ user_id: @user.id })
      render json: { user: UserSerializer.new(@user), jwt: @token }, status: :accepted
    else
      render json: { message: 'Invalid username or password' }, status: :unauthorized
    end
  end

  private

  def user_login_params
    params.require(:user).permit(:username, :password)
  end
end

还有我的应用程序控制器(我怀疑问题就在这里,并且与我编码和解码令牌的方式有关):

class ApplicationController < ActionController::API
  before_action :authorized

  def encode_token(payload) 
    JWT.encode(payload, ENV["jwt_secret"]) 
  end

  def auth_header
    request.headers['Authorization']
  end

  def decoded_token
    if auth_header()
      token = auth_header.split(' ')[1] 
      begin
        JWT.decode(token, ENV["jwt_secret"], true, algorithm: 'HS256')
      rescue JWT::DecodeError
        nil
      end
    end
  end

  def current_user
    if decoded_token()
      user_id = decoded_token[0]['user_id'] 
      @user = User.find_by(id: user_id)
    else
      nil
    end
  end

  def logged_in?
    !!current_user
  end

  def authorized
    render json: { message: 'Please log in' }, status: :unauthorized unless logged_in?
  end
end

从我的前端,我使用 fetch 方法来 POST 到 /users/ 端点,如下所示:

export const signupUser = (username, password) => {
  return(dispatch) => {
    const data = {user: {username, password} }
    fetch('http://localhost:3000/api/v1/users',{
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        Accept: 'application/json'
      },
      body: JSON.stringify(data)
    })
    .then(r=>r.json())
    .then(r=>{
      localStorage.setItem('jwt', r.jwt)
      dispatch({
        type: SET_CURRENT_USER,
        payload: r.user
      })
    })
  }
}

抱歉,这是冗长的。我想包括所有必要的代码来解决这个问题。任何援助将不胜感激。

标签: ruby-on-railsreactjsauthenticationjwt

解决方案


我注意到当您使用函数创建用户时,您没有保存用户对象。请使用to方法检查app/controllers/api/v1/users_controller.rb并修改以下内容validsave

def create
    @user = User.create(user_params)
    if @user.valid?
      @token = encode_token(user_id: @user.id)
      render json: { user: UserSerializer.new(@user), jwt: @token }, status: :created
    else
      render json: {error: "Could not create user"}, status: :unprocessible_entity
    end
  end

将行更改@user.valid?@user.save

def create
    @user = User.create(user_params)
    if @user.save
      @token = encode_token(user_id: @user.id)
      render json: { user: UserSerializer.new(@user), jwt: @token }, status: :created
    else
      render json: {error: "Could not create user"}, status: :unprocessible_entity
    end
  end

请注意 .valid? 用于验证和检查是否有任何错误,.save 用于保存。您只是在检查验证而不是实际保存,验证会自动发生,因此这里不需要此方法。


推荐阅读