Rust,返回引用当前函数所拥有的数据的值

628mspwn  于 2023-01-02  发布在  其他
关注(0)|答案(2)|浏览(184)

我检查了这个问题的论坛,我发现了一些答案,但任何这种情况是不同的,不为我工作。
我遇到此错误的问题:

let test = PasswordHash::new(&hashed_password).clone().unwrap();
   |                                      ---------------- `hashed_password` is borrowed here
53 |         // Ok(PasswordHash::new(&hashed_password).unwrap())
54 |         Ok(test)
   |         ^^^^^^^^ returns a value referencing data owned by the current function

我完全知道这个错误是什么意思。我知道问题出在哪里,我甚至知道是什么造成的。但是我不知道如何修复它。
我的想法是不重复负责生成PasswordHash的部分代码。我决定创建单独的函数来完成这个任务。
我的代码如下:

use argon2::{
    password_hash::{
        rand_core::OsRng,
        PasswordHash, PasswordHasher, PasswordVerifier, SaltString, Error
    },
    Argon2,
};

struct AlgorithmData {
    version: u32,
    params: String,
    algorithm_type: String,
}
impl AlgorithmData {
    fn new() -> Self {
        let example_string = "example_string";
        let password_hash = Hasher::get_passwordhash_object(&example_string).unwrap();

        AlgorithmData { version: password_hash.version.unwrap(),
                        params: password_hash.params.to_string(),
                        algorithm_type: password_hash.algorithm.to_string() }
    }
}
pub struct Hasher {}

impl Hasher {    
    pub fn hash_string(string_to_hash: &str) -> Result<String, Error> {
        let parsed_hash_password = Hasher::get_passwordhash_object(string_to_hash)?;

        let result = format!("{}${}",
                                     parsed_hash_password.salt.unwrap().to_string(),
                                     parsed_hash_password.hash.unwrap().to_string());
        
        Ok(result)
    }

    fn get_passwordhash_object(string_to_hash: &str) -> Result<PasswordHash, Error> {
        let bytes_to_hash = string_to_hash.as_bytes();
        
        let salt = SaltString::generate(&mut OsRng);
        let argon2 = Argon2::default();

        let hashed_password = argon2.hash_password(&bytes_to_hash,
                                                           &salt)?.to_string();
        
        let test = PasswordHash::new(&hashed_password).clone().unwrap();
        // Ok(PasswordHash::new(&hashed_password).unwrap()) --> here too is problem
        Ok(test) // here is the same problem
    }

    pub fn compare_string_to_hash(string_to_compare: &String,
                                  hash_to_compare: &String) -> Result<bool, Error> {
        let bytes_to_compare = string_to_compare.as_bytes();
        let bytes_from_hash = PasswordHash::new(&hash_to_compare).unwrap();

        Ok(Argon2::default().verify_password(&bytes_to_compare,
                                             &bytes_from_hash).is_ok())
    }    
}

就像你看到的主要问题是变量:hashed_password及其在新对象PasswordHash中引用。
我尝试使用copy函数来克隆hashed_password变量或对象PasswordHash。第二件事是尝试使用lifetime参数,如〈'a〉。第三个想法是使用Box::new来尝试直接访问内存。
我需要帮助来解决这个问题。我已经阅读了文档。但是仍然没有更多的想法来解决这个问题。
错误编号:E0515很好地解释了原因。

kkih6yb8

kkih6yb81#

这里肯定有一个生存期问题,在您的例子中,PasswordHash的生存期依赖于SaltString,因此,如果您想将PasswordHash的引用发送给调用者,最好将SaltString作为函数get_passwordhash_object的参数。
下面是从您的代码中派生的最小示例:

use argon2::{
    password_hash::{rand_core::OsRng, Error, PasswordHash, PasswordHasher, SaltString},
    Argon2,
};
pub struct Hasher {}

impl Hasher {
    fn get_passwordhash_object<'a>(
        bytes_to_hash: &'a [u8],
        salt: &'a SaltString,
    ) -> Result<PasswordHash<'a>, Error> {
        let argon2 = Argon2::default();

        let hashed_password = argon2.hash_password(&bytes_to_hash, salt).unwrap();
        Ok(hashed_password)
    }
}

fn main() {
    let salt = SaltString::generate(&mut OsRng);
    let hash = Hasher::get_passwordhash_object("something".as_bytes(), &salt);
    println!("{:?}", hash);
}
u5rb5r59

u5rb5r592#

如果你查看PasswordHash::new的文档,你会发现它返回一个和参数一样的结构体,在你的例子中,test变量的生命周期取决于hashed_password的生命周期,而hashed_password本身又取决于拥有它的数据的salt的生命周期。
get_passwordhash_object中,您不能返回PasswordHash类型并丢弃salt,您需要返回两者,或者将数据转换为拥有其数据的其他内容。
一种解决方案是将PasswordHash序列化为PasswordHashString,因为此类型拥有其数据

pub fn hash_string(string_to_hash: &str) -> Result<String, Error> {
    let parsed_hash_password =
        Hasher::get_passwordhash_object(string_to_hash)?;

    let result = format!(
        "{}${}",
        parsed_hash_password.salt().unwrap().to_string(),
        parsed_hash_password.hash().unwrap().to_string()
    );

    Ok(result)
}

fn get_passwordhash_object(
    string_to_hash: &str,
) -> Result<PasswordHashString, Error> {
    let bytes_to_hash = string_to_hash.as_bytes();

    let salt = SaltString::generate(&mut OsRng);
    let argon2 = Argon2::default();

    let hashed_password =
        argon2.hash_password(&bytes_to_hash, &salt)?.to_string();

    let test = PasswordHash::new(&hashed_password).clone().unwrap();
    Ok(test.serialize())
}

pub fn compare_string_to_hash(
    string_to_compare: &String,
    hash_to_compare: &String,
) -> Result<bool, Error> {
    let bytes_to_compare = string_to_compare.as_bytes();
    let bytes_from_hash = PasswordHash::new(&hash_to_compare).unwrap();

    Ok(Argon2::default()
        .verify_password(&bytes_to_compare, &bytes_from_hash)
        .is_ok())
}

相关问题