【问题标题】:Struggling to implement Devise user roles with rails backend, react + redux frontend努力使用 rails 后端、react + redux 前端实现设计用户角色
【发布时间】:2021-11-04 18:12:20
【问题描述】:

我正在构建一个应用程序,其中有两种类型的用户,memberbusiness_event。我正在努力实现这一点。我有一个用户的注册表单,他们可以从下拉菜单中选择他们是“会员”还是“企业或活动”。当我尝试注册特定角色时,我的 Rails 控制台总是显示“角色”是“成员”(我分配的默认值)。

在我的 Rails 后端,我添加了设计 gem 和此迁移:

class AddRoleToUsers < ActiveRecord::Migration[6.1]
  def change
    add_column :users, :role, :integer
  end
end

然后我将 User 模型更改为以下内容:

class User < ApplicationRecord
    has_secure_password
    enum role: [:member, :business_event]
    after_initialize :set_default_role, :if => :new_record?

    def set_default_role
      self.role ||= :member
    end
end

在我的 react 前端,这是我想用来注册用户的表单:

import React from 'react'
import { connect } from 'react-redux'
import { updateSignupForm } from "../../actions/signupForm.js"
import { signup } from "../../actions/currentUser.js"

const Signup = ({ signupFormData, updateSignupForm, signup }) => {

    const handleUserInfoInputChange = event => {
      const { name, value } = event.target
      const updatedFormInfo = {
        ...signupFormData,
        [name]: value
      }
      updateSignupForm(updatedFormInfo)
    }
  
     
  
    const handleSubmit = event => {
      event.preventDefault()
       
      signup(signupFormData)
    }
  
    return (
      <div>
        <h1>Sign Up </h1>

      <form onSubmit={handleSubmit}>
        <div className="ui input">
        <select>
        <option value={signupFormData.role}>Member</option>
        <option value={signupFormData.role}>Business or Event</option>
        </select>
         <input placeholder="username" value={signupFormData.username} name="username" type="text" onChange={handleUserInfoInputChange} /> 
        <input placeholder="password" value={signupFormData.password} name="password" type="text" onChange={handleUserInfoInputChange} /> 
         <input placeholder="email" value={signupFormData.email} name="email" type="text" onChange={handleUserInfoInputChange}/><br/><br/>

        <button className="button button-signup" type="submit" value="Sign Up" > Sign up</button>

        </div>
      </form>
      </div>
    
    )
  }
  
  const mapStateToProps = state => {
    return {
      signupFormData: state.signupForm
    }
  }
  
  export default connect(mapStateToProps, { updateSignupForm, signup } )(Signup)

在我的signupForm reducer 中,我决定将“role”的初始值设置为“0”,因为它在后端是一个整数。我不确定这是否是我出错的地方:

  const initialState = {
    username: "",
    password: "",
    email: "",
    role: 0
  }
  
  export default (state=initialState, action) => {
    switch (action.type) {
      case "UPDATE_SIGNUP_FORM":
        return action.formData
      case "RESET_SIGNUP_FORM":
        return initialState
      default:
        return state
    }
  }

我不确定为什么用户总是恢复为“成员”的默认角色。任何帮助将不胜感激。

【问题讨论】:

  • 检查后端是否需要“0”或“1”形式的角色。它实际上是这样发生的。
  • 是的,我查过了。当我在控制台中运行 User.roles 时,我得到了 User.roles =&gt; {"member"=&gt;0, "business_event"=&gt;1}
  • 相关控制器在做什么?角色如何传递给用户模型?
  • 是的 - 你的前端应该只使用字符串值,只有后端模型/数据库应该知道它们映射到的数值。见edgeapi.rubyonrails.org/classes/ActiveRecord/Enum.html
  • 非常感谢您

标签: reactjs ruby-on-rails devise authorization roles


【解决方案1】:

在添加其他功能之前,您确实应该只专注于正确安装 Devise 并为您的基本身份验证系统添加测试。隐藏你的工作并回溯。

首先运行生成器生成配置文件:

rails g devise:install

然后设置您的模型:

rails g devise user

这增加了以下内容:

class User < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable
end

您不希望 has_secure_password 是 Rails 自己的密码加密宏,用于构建您自己的身份验证系统。 Devise database_authenticable 模块已经涵盖了您。现在写integration tests,其中包括注册和登录而不涉及反应。在保持理智方面,这将带来巨大的回报。

现在您可以真正开始使用角色功能了。

在数据库级别添加具有默认值的枚举列:

class AddRoleToUsers < ActiveRecord::Migration[6.1]
  def change
    add_column :users, :role, :integer, default: 0
  end
end

使用回调设置属性默认值是一种过时且笨拙的方法,具有许多已知的缺陷。除非您确实需要在应用程序级别评估默认值,否则请使用数据库默认值 - 在这种情况下,您希望通过 attributes api 进行评估。

将枚举宏添加到模型中:

class User < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable
  enum role: [:member, :business_event]
end

如果您真的希望能够在注册用户时从参数中设置角色,您需要在设计中将该参数列入白名单:

class ApplicationController < ActionController::Base
  before_action :configure_permitted_parameters, if: :devise_controller?

  protected

  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up, keys: [:role])
  end
end

但是您需要仔细考虑这样做的安全隐患,因为它可以让恶意用户通过简单地通过 cURL 发送请求或操纵输入来授予自己提升的权限。这现在可能不相关,但如果您曾经添加过管理员角色,请记住这一点。

角色的整数值也是一个只有模型才能知道的实现细节。您的前端和其他所有东西(例如控制器)应该只知道键:

const initialState = {
  username: "",
  password: "",
  email: "",
  role: "member"
}

【讨论】:

  • 非常感谢您
猜你喜欢
  • 2021-04-28
  • 1970-01-01
  • 2020-12-14
  • 1970-01-01
  • 2019-04-19
  • 1970-01-01
  • 2023-04-03
  • 1970-01-01
  • 2013-10-23
相关资源
最近更新 更多