Biên Dịch : Nguyễn Hoàng Đạt - Lớp Java07
Email : hoangdat3179@gmail.com
Bài viết gốc : https://www.baeldung.com/spring-security-registration-password-encoding-bcrypt

1. Tổng quan

Trong hướng dẫn này, chúng ta sẽ thảo luận về một phần quan trọng của quy trình đăng ký, mã hóa mật khẩu, về cơ bản là không lưu trữ mật khẩu ở dạng văn bản thuần túy. Có một vài cơ chế encoding được Spring Security hỗ trợ, và trong bài viết này, chúng ta sẽ sử dụng BCrypt, vì nó thường là giải pháp tốt nhất hiện có. Hầu hết các cơ chế khác, chẳng hạn như MD5PasswordEncoder và ShaPasswordEncoder, sử dụng các thuật toán yếu hơn và hiện không còn được dùng nữa.

2. Xác định Bộ mã hóa mật khẩu

Chúng ta sẽ bắt đầu bằng cách xác định BCryptPasswordEncoder đơn giản như với Bean trong cấu hình của chúng ta:

@Bean
public PasswordEncoder encoder() {
    return new BCryptPasswordEncoder();
}

Các triển khai cũ hơn, chẳng hạn như SHAPasswordEncoder, yêu cầu máy khách chuyển giá trị muối khi mã hóa mật khẩu.

BCrypt, tuy nhiên, nội bộ sẽ tạo ra một muối ngẫu nhiên thay thế. Điều này rất quan trọng để hiểu vì nó có nghĩa là mỗi cuộc gọi sẽ có một kết quả khác nhau, vì vậy chúng ta chỉ cần mã hóa mật khẩu một lần. Để làm cho việc tạo muối ngẫu nhiên này hoạt động, BCrypt sẽ lưu trữ muối bên trong chính giá trị băm. Ví dụ: giá trị băm sau:

$2a$10$ZLhnHxdpHETcxmtEStgpI./Ri1mksgJ9iDP36FmfMdYyVg9g0b2dq

Tách ba trường bằng $:

  1. “2a” đại diện cho phiên bản thuật toán Bcrypt
  2. “10” đại diện cho sức mạnh của thuật toán
  3. Phần ‘ZLhnHxdpHETcxmtEStgpI.’ thực sự là muối được tạo ngẫu nhiên. Về cơ bản, 22 chữ cái đầu tiên là muối. Phần còn lại của trường cuối cùng là phiên bản băm thực tế của văn bản thuần túy.

Ngoài ra, hãy lưu ý rằng thuật toán BCrypt tạo ra chuỗi độ dài 60, vì vậy chúng tôi cần đảm bảo rằng mật khẩu sẽ được lưu trữ trong một cột có thể chứa nó. Một lỗi phổ biến là tạo một cột có độ dài khác, sau đó gặp lỗi Tên người dùng hoặc Mật khẩu không hợp lệ tại thời điểm xác thực.

3.Mã hóa mật khẩu khi đăng ký

Chúng ta sẽ sử dụng PasswordEncoder trong UserService của chúng ta để băm mật khẩu trong quá trình đăng ký người dùng:

Ví dụ 3.1. Người dùng đã băm mật khẩu

@Autowired
private PasswordEncoder passwordEncoder;

@Override
public User registerNewUserAccount(UserDto accountDto) throws EmailExistsException {
    if (emailExist(accountDto.getEmail())) {
        throw new EmailExistsException(
          "There is an account with that email adress:" + accountDto.getEmail());
    }
    User user = new User();
    user.setFirstName(accountDto.getFirstName());
    user.setLastName(accountDto.getLastName());
    
    user.setPassword(passwordEncoder.encode(accountDto.getPassword()));
    
    user.setEmail(accountDto.getEmail());
    user.setRole(new Role(Integer.valueOf(1), user));
    return repository.save(user);
}

4.Mã hóa mật khẩu trên xác thực

Bây giờ chúng ta sẽ xử lý nửa còn lại của quá trình này và mã hóa mật khẩu khi người dùng xác thực. Đầu tiên, chúng ta cần đưa Bean bộ mã hóa mật khẩu mà chúng ta đã xác định trước đó vào nhà cung cấp xác thực của mình:

@Autowired
private UserDetailsService userDetailsService;

@Bean
public DaoAuthenticationProvider authProvider() {
    DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
    authProvider.setUserDetailsService(userDetailsService);
    authProvider.setPasswordEncoder(encoder());
    return authProvider;
}

Cấu hình bảo mật rất đơn giản:

  • Chúng ta đưa việc triển khai dịch vụ chi tiết người dùng của chúng ta
  • Chúng ta xác định một nhà cung cấp xác thực tham chiếu đến dịch vụ chi tiết của chúng ta
  • Chúng tôi cũng bật bộ mã hóa mật khẩu

Cuối cùng, chúng ta cần tham khảo nhà cung cấp auth này trong cấu hình XML bảo mật của chúng ta:

<authentication-manager>
    <authentication-provider ref="authProvider" />
</authentication-manager>

Hoặc, nếu chúng ta đang sử dụng cấu hình Java:

@Configuration
@ComponentScan(basePackages = { "com.baeldung.security" })
@EnableWebSecurity
public class SecSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authProvider());
    }
    
    ...
}

5. Tổng kết

Như vậy, qua bài viết chúng ta đã học được cách mã hóa mật khẩu để tăng cường bảo mật với Spring security.