当前位置: 首页 > 知识库问答 >
问题:

Java更改用于序列化的属性类型

易宣
2023-03-14

{“登录”:“testuser”,“邮件”:“testuser@gmail.com”,“密码”:“123abc”}

现在的问题是:我听说我们不应该将密码存储为字符串,而是在Java中存储为char数组,所以我就是这么做的。

下面是我的用户

package com.mailReminder.restservice.model;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonValue;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;

import javax.persistence.*;
import java.util.Arrays;

@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    private String login;
    private String mail;

    private char[] password;

    private byte[] salt;

    public User(String login, String mail, char[] password) {
        this.login = login;
        this.mail = mail;
        this.password = password;
    }

    public User() {
        this.id = 0L;
        this.login = "";
        this.mail = "";
        this.password = null;
        this.salt = null;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getLogin() {
        return login;
    }

    public void setLogin(String login) {
        this.login = login;
    }

    public String getMail() {
        return mail;
    }

    public void setMail(String mail) {
        this.mail = mail;
    }

    public char[] getPassword() {
        return password;
    }

    public void setPassword(char[] password) {
        this.password = password;
    }

    public byte[] getSalt() {
        return salt;
    }

    public void setSalt(byte[] salt) {
        this.salt = salt;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", login='" + login + '\'' +
                ", mail='" + mail + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}
package com.mailReminder.restservice.security;

import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;

public class PasswordSecurer{

    public static byte[] getSalt() {
        SecureRandom random = new SecureRandom();
        byte[] salt = new byte[16];
        random.nextBytes(salt);

        return salt;
    }

    public static byte[] hashPassword(char[] password, byte[] salt) {
        int iterationCount = 65536;
        int keyLength = 640;

        KeySpec spec = new PBEKeySpec(password, salt, iterationCount, keyLength);
        SecretKeyFactory factory = null;
        try {
            factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
            return factory.generateSecret(spec).getEncoded();
        } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
            e.printStackTrace();
        }

        return null;
    }
}
package com.mailReminder.restservice.controller;

import com.mailReminder.restservice.model.User;
import com.mailReminder.restservice.repository.UserRepository;
import com.mailReminder.restservice.security.PasswordSecurer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.Arrays;

@RestController
public class UserController {
    private final UserRepository userRepository;

    @Autowired
    public UserController(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @PostMapping("/register")
    public ResponseEntity<Object> register(@RequestBody User newUser) {
        byte[] salt = PasswordSecurer.getSalt();
        byte[] hashedPassword = PasswordSecurer.hashPassword(Arrays.toString(newUser.getPassword()).toCharArray(), salt);
        System.out.println(Arrays.toString(hashedPassword));
        if (hashedPassword == null)
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("");

        if (userRepository.findByLogin(newUser.getLogin()) != null)
            return ResponseEntity.status(HttpStatus.BAD_REQUEST)
                    .body("{\"errorCode\":400,\"errorMessage\":\"User already exists\"}");

        System.out.println(Arrays.toString(hashedPassword));
        newUser.setPassword(Arrays.toString(hashedPassword).toCharArray());
        newUser.setSalt(salt);
        userRepository.save(newUser);

        return ResponseEntity.ok(newUser);
    }

    @GetMapping("/register")
    public @ResponseBody
    Iterable<User> getAllUsers() {

        return userRepository.findAll();
    }
}

在决定接受json作为请求之前,我使用byte[]作为密码,这就是它在数据库中的样子,也是我希望它现在的样子。

bAz}+øeí'méjé7héubfpléa4lypyí:'-eqé'éeó4é'6íka©§_~9w©Cx§.

但是我不能将它更改为User类中的byte[],因为Jackson会崩溃,出现错误:JSON parse error:不能从字符串反序列化byte[]类型的值

所以我的问题是:我能做什么,使我的密码看起来再次散列,而不把char[]更改为string?

共有1个答案

郭琨
2023-03-14

取字节数组并将其转换为base64:

byte[] bytes = {-108, -71, 126, -39, -6, 65, 50, 42, -51, 55, -88, -121, -103, 55, 109, 22, 12, -21, 33, 72, 122, -127, -31, 90, 49, 75, 90, -79, 83, -99, -50, -100, -66, 29, 45, -60, 8, 41, 1, 115, -65, -124, -5, -47, 71, -105, 28, -68, -128, 12, -111, -93, -27, -102, 51, -119, -99, 49, -23, -27, 96, -42, -128, 124, 61, -87, 17, -15, -46, -85, -16, -62, 106, -1, -79, 79, 53, 108, -56, -128};

String output = Base64.getEncoder().encodeToString(bytes);

System.out.println( "base64 is " + output );

然后你会得到:

base64 is lLl+2fpBMirNN6iHmTdtFgzrIUh6geFaMUtasVOdzpy+HS3ECCkBc7+E+9FHlxy8gAyRo+WaM4mdMenlYNaAfD2pEfHSq/DCav+xTzVsyIA=

将其作为字符串存储在数据库中,并仅与之进行比较。密码应该是一种方法--你现在需要一种方法来重置密码,以防忘记密码。

 类似资料:
  • 问题内容: 我的课有一个属性’PropertyA’,我希望它在序列化时在JSON对象中显示为’PropertyB’。我可以使用某种属性吗? 问题答案: 对于与使用: 确保您的课程也用属性修饰。 如果您使用的是JavaScriptSerializer,则需要创建派生的实现

  • 我有以下Java超类,每个属性都有构造函数、getter和setter: 和一个car子类,它扩展了vehicle超类,并具有几个独特的属性: 我创建一个新的vehicle对象链表,并向其中添加一个新的car对象: 我可以用下面这样的函数更改属于vehicle超级类的任何属性: 但是当我试图创建一个类似的函数来更改其中一个子类属性时,我得到了这个错误:“方法setWheels(int)对于类型Ve

  • 我有一个MyClass,它的属性类型为MyAttribute。该类由MySubClass继承,其属性类型为MySubAttribute。MySubAttribute是MyAttribute的子类: 现在假设我有以下代码: 如何生成MySubAttribute类型的返回值?

  • 问题内容: 如果我尝试序列化静态属性会怎样? 谢谢 问题答案: 从这篇文章: 提示1:处理静态变量 Java类通常在静态类变量中包含一些全局相关的值。我们不会进入有关全局变量是否适当的争论的悠久历史- 只能说程序员继续发现它们有用,而纯粹主义者建议的替代方案并不总是可行的。 对于声明时初始化的静态变量,序列化不会出现任何特殊问题。第一次使用该类时,相关变量将设置为正确的值。 某些静态无法通过这种方

  • 我是XSLT新手,希望能得到一些帮助。 我目前有一个XML,它包含以下格式的多个副本: 我的任务是替换id属性的值。我需要根据代码的数字部分改变这个值。如果值大于850000,格式应该改为USA868509。如果该值小于850000,则将id值更改为仅包括数字。XML中的其余值应保持完全相同。 我目前拥有以下xslt: 我很难确定要更改的值,因为XSLT不执行变量循环。有没有办法更改XSLT以获得