跳至内容 跳至搜索

这是混合在 Active Record 模型中的关注点,使其可加密。它添加了encrypts 属性声明,以及加密和解密记录的 API。

方法
A
C
D
E
G
O
P
S
V

常量

ORIGINAL_ATTRIBUTE_PREFIX = "original_"
 

实例公共方法

add_length_validation_for_encrypted_columns()

# File activerecord/lib/active_record/encryption/encryptable_record.rb, line 132
def add_length_validation_for_encrypted_columns
  encrypted_attributes&.each do |attribute_name|
    validate_column_size attribute_name
  end
end

ciphertext_for(attribute_name)

返回attribute_name的密文。

# File activerecord/lib/active_record/encryption/encryptable_record.rb, line 157
def ciphertext_for(attribute_name)
  if encrypted_attribute?(attribute_name)
    read_attribute_before_type_cast(attribute_name)
  else
    read_attribute_for_database(attribute_name)
  end
end

decrypt()

解密所有可加密的属性并保存更改。

# File activerecord/lib/active_record/encryption/encryptable_record.rb, line 171
def decrypt
  decrypt_attributes if has_encrypted_attributes?
end

deterministic_encrypted_attributes()

返回模型类中所有确定性可加密属性的列表。

# File activerecord/lib/active_record/encryption/encryptable_record.rb, line 58
def deterministic_encrypted_attributes
  @deterministic_encrypted_attributes ||= encrypted_attributes&.find_all do |attribute_name|
    type_for_attribute(attribute_name).deterministic?
  end
end

encrypt()

加密所有可加密属性并保存更改。

# File activerecord/lib/active_record/encryption/encryptable_record.rb, line 166
def encrypt
  encrypt_attributes if has_encrypted_attributes?
end

encrypt_attribute(name, key_provider: nil, key: nil, deterministic: false, support_unencrypted_data: nil, downcase: false, ignore_case: false, previous: [], compress: true, compressor: nil, **context_properties)

# File activerecord/lib/active_record/encryption/encryptable_record.rb, line 84
def encrypt_attribute(name, key_provider: nil, key: nil, deterministic: false, support_unencrypted_data: nil, downcase: false, ignore_case: false, previous: [], compress: true, compressor: nil, **context_properties)
  encrypted_attributes << name.to_sym

  decorate_attributes([name]) do |name, cast_type|
    scheme = scheme_for key_provider: key_provider, key: key, deterministic: deterministic, support_unencrypted_data: support_unencrypted_data, \
      downcase: downcase, ignore_case: ignore_case, previous: previous, compress: compress, compressor: compressor, **context_properties

    ActiveRecord::Encryption::EncryptedAttributeType.new(scheme: scheme, cast_type: cast_type, default: columns_hash[name.to_s]&.default)
  end

  preserve_original_encrypted(name) if ignore_case
  ActiveRecord::Encryption.encrypted_attribute_was_declared(self, name)
end

encrypted_attribute?(attribute_name)

返回给定属性是否已加密。

# File activerecord/lib/active_record/encryption/encryptable_record.rb, line 146
def encrypted_attribute?(attribute_name)
  name = attribute_name.to_s
  name = self.class.attribute_aliases[name] || name

  return false unless self.class.encrypted_attributes&.include? name.to_sym

  type = type_for_attribute(name)
  type.encrypted? read_attribute_before_type_cast(name)
end

encrypts(*names, key_provider: nil, key: nil, deterministic: false, support_unencrypted_data: nil, downcase: false, ignore_case: false, previous: [], compress: true, compressor: nil, **context_properties)

加密name属性。

选项

  • :key_provider - 用于提供加密和解密密钥的密钥提供者。默认值为ActiveRecord::Encryption.key_provider

  • :key - 用于从其派生密钥的密码。这是:key_provider的简写,它提供派生密钥。两者不能同时使用。

  • :deterministic - 默认情况下,加密不是确定性的。它将为每个加密操作使用随机初始化向量。这意味着使用相同的密钥两次加密相同的内容将生成不同的密文。当设置为true时,它将基于加密内容生成初始化向量。这意味着相同的内容将生成相同的密文。这使得可以使用 Active Record 查询加密文本。默认情况下,确定性加密将使用最旧的加密方案来加密新数据。可以通过设置deterministic: { fixed: false }来更改此行为。这将使其使用最新的加密方案来加密新数据。

  • :support_unencrypted_data - 如果‘config.active_record.encryption.support_unencrypted_data`为true,则可以将其设置为false来选择退出此属性的未加密数据支持。这在加密一列并希望禁用未加密数据支持而无需调整全局设置的情况下很有用。

  • :downcase - 为真时,它会自动将加密内容转换为小写。这允许在查询数据时有效地忽略大小写。请注意,大小写将丢失。如果要保留大小写,请使用:ignore_case

  • :ignore_case - 为真时,它的行为类似于:downcase,但它还会在专门指定的列 +original_<name>+ 中保留原始大小写。读取加密内容时,将提供带原始大小写的版本。但是您仍然可以执行忽略大小写的查询。此选项只能在:deterministic为真时使用。

  • :context_properties - 当此属性被加密和解密时,将覆盖Context设置的附加属性。例如:encryptor:cipher:message_serializer:等。

  • :previous - 以前的加密方案列表。提供后,它们将在尝试读取属性时按顺序使用。列表中的每个条目都可以包含encrypts支持的属性。此外,在使用确定性加密时,它们将用于生成要在查询中检查的其他密文。

# File activerecord/lib/active_record/encryption/encryptable_record.rb, line 49
def encrypts(*names, key_provider: nil, key: nil, deterministic: false, support_unencrypted_data: nil, downcase: false, ignore_case: false, previous: [], compress: true, compressor: nil, **context_properties)
  self.encrypted_attributes ||= Set.new # not using :default because the instance would be shared across classes

  names.each do |name|
    encrypt_attribute name, key_provider: key_provider, key: key, deterministic: deterministic, support_unencrypted_data: support_unencrypted_data, downcase: downcase, ignore_case: ignore_case, previous: previous, compress: compress, compressor: compressor, **context_properties
  end
end

global_previous_schemes_for(scheme)

# File activerecord/lib/active_record/encryption/encryptable_record.rb, line 78
def global_previous_schemes_for(scheme)
  ActiveRecord::Encryption.config.previous_schemes.filter_map do |previous_scheme|
    scheme.merge(previous_scheme) if scheme.compatible_with?(previous_scheme)
  end
end

override_accessors_to_preserve_original(name, original_attribute_name)

# File activerecord/lib/active_record/encryption/encryptable_record.rb, line 109
def override_accessors_to_preserve_original(name, original_attribute_name)
  include(Module.new do
    define_method name do
      if ((value = super()) && encrypted_attribute?(name)) || !ActiveRecord::Encryption.config.support_unencrypted_data
        send(original_attribute_name)
      else
        value
      end
    end

    define_method "#{name}=" do |value|
      self.send "#{original_attribute_name}=", value
      super(value)
    end
  end)
end

preserve_original_encrypted(name)

# File activerecord/lib/active_record/encryption/encryptable_record.rb, line 98
def preserve_original_encrypted(name)
  original_attribute_name = "#{ORIGINAL_ATTRIBUTE_PREFIX}#{name}".to_sym

  if !ActiveRecord::Encryption.config.support_unencrypted_data && !column_names.include?(original_attribute_name.to_s)
    raise Errors::Configuration, "To use :ignore_case for '#{name}' you must create an additional column named '#{original_attribute_name}'"
  end

  encrypts original_attribute_name
  override_accessors_to_preserve_original name, original_attribute_name
end

scheme_for(key_provider: nil, key: nil, deterministic: false, support_unencrypted_data: nil, downcase: false, ignore_case: false, previous: [], **context_properties)

# File activerecord/lib/active_record/encryption/encryptable_record.rb, line 70
def scheme_for(key_provider: nil, key: nil, deterministic: false, support_unencrypted_data: nil, downcase: false, ignore_case: false, previous: [], **context_properties)
  ActiveRecord::Encryption::Scheme.new(key_provider: key_provider, key: key, deterministic: deterministic,
    support_unencrypted_data: support_unencrypted_data, downcase: downcase, ignore_case: ignore_case, **context_properties).tap do |scheme|
    scheme.previous_schemes = global_previous_schemes_for(scheme) +
    Array.wrap(previous).collect { |scheme_config| ActiveRecord::Encryption::Scheme.new(**scheme_config) }
  end
end

source_attribute_from_preserved_attribute(attribute_name)

给定一个属性名,如果它是一个保留的属性,则返回源属性的名称。

# File activerecord/lib/active_record/encryption/encryptable_record.rb, line 65
def source_attribute_from_preserved_attribute(attribute_name)
  attribute_name.to_s.sub(ORIGINAL_ATTRIBUTE_PREFIX, "") if attribute_name.start_with?(ORIGINAL_ATTRIBUTE_PREFIX)
end

validate_column_size(attribute_name)

# File activerecord/lib/active_record/encryption/encryptable_record.rb, line 138
def validate_column_size(attribute_name)
  if limit = columns_hash[attribute_name.to_s]&.limit
    validates_length_of attribute_name, maximum: limit
  end
end