Skip to main content

Command Palette

Search for a command to run...

Bài 5: Xác thực cơ bản: Form-based và HTTP Basic Authentication

Published
10 min readView as Markdown

1. Giới thiệu về xác thực cơ bản

Khái niệm và vai trò của form-based và HTTP Basic Authentication

Form-based Authentication: Form-based authentication là một phương thức xác thực sử dụng một biểu mẫu (form) đăng nhập trên trang web để thu thập thông tin đăng nhập từ người dùng. Người dùng sẽ nhập tên người dùng và mật khẩu vào biểu mẫu, sau đó gửi yêu cầu đăng nhập đến máy chủ để xác thực. Phương thức này thường được sử dụng trong các ứng dụng web để cung cấp một giao diện thân thiện và dễ sử dụng cho người dùng. Nó cho phép tùy chỉnh giao diện trang đăng nhập và trang lỗi xác thực, giúp cải thiện trải nghiệm người dùng.

HTTP Basic Authentication: HTTP Basic Authentication là một phương thức xác thực đơn giản được tích hợp trong giao thức HTTP. Thông tin đăng nhập của người dùng (tên người dùng và mật khẩu) được mã hóa bằng Base64 và gửi trong tiêu đề của mỗi yêu cầu HTTP. Máy chủ sẽ giải mã thông tin này và xác thực người dùng. HTTP Basic Authentication dễ triển khai và không yêu cầu bất kỳ trang đăng nhập tùy chỉnh nào, nhưng không an toàn khi sử dụng trên các kết nối không được mã hóa (HTTP thay vì HTTPS) vì thông tin đăng nhập có thể bị chặn và giải mã bởi bên thứ ba.

Vai trò của form-based và HTTP Basic Authentication:

  • Form-based Authentication: Cung cấp giao diện thân thiện cho người dùng để đăng nhập, dễ dàng tùy chỉnh và tích hợp với các hệ thống khác.

  • HTTP Basic Authentication: Đơn giản và dễ triển khai, thường được sử dụng trong các dịch vụ web hoặc API nơi không yêu cầu giao diện đăng nhập tùy chỉnh.

2. Cấu hình HTTP Basic Authentication

Cách cấu hình HTTP Basic Authentication trong Spring Security

Để cấu hình HTTP Basic Authentication trong Spring Security, bạn cần thực hiện các bước sau:

  1. Thêm dependency Spring Security vào dự án.

  2. Tạo lớp cấu hình bảo mật và bật HTTP Basic Authentication.

  3. Cấu hình quyền truy cập cho các URL.

Ví dụ cấu hình HTTP Basic Authentication:

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/public/**").permitAll()
                .anyRequest().authenticated()
                .and()
            .httpBasic();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
            .withUser("user").password("{noop}password").roles("USER")
            .and()
            .withUser("admin").password("{noop}admin").roles("ADMIN");
    }
}
Ví dụ thực tế

Trong ví dụ trên, lớp SecurityConfig cấu hình HTTP Basic Authentication cho ứng dụng Spring Boot. Tất cả các yêu cầu HTTP sẽ yêu cầu xác thực, trừ các yêu cầu đến các URL bắt đầu bằng /public/**, cho phép truy cập mà không cần xác thực. Thông tin người dùng được lưu trữ trong bộ nhớ với các tên người dùng và mật khẩu được định nghĩa trong phương thức configure(AuthenticationManagerBuilder auth).

3. Cấu hình form-based Authentication

Cách cấu hình form-based login

Để cấu hình form-based login trong Spring Security, bạn cần thực hiện các bước sau:

  1. Thêm dependency Spring Security vào dự án.

  2. Tạo lớp cấu hình bảo mật và bật form-based login.

  3. Tạo các trang đăng nhập và đăng xuất tùy chỉnh nếu cần.

Ví dụ cấu hình form-based login:

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/public/**").permitAll()
                .anyRequest().authenticated()
                .and()
            .formLogin()
                .loginPage("/login")
                .permitAll()
                .and()
            .logout()
                .permitAll();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
            .withUser("user").password("{noop}password").roles("USER")
            .and()
            .withUser("admin").password("{noop}admin").roles("ADMIN");
    }
}
Tùy chỉnh trang login và logout (ví dụ sử dụng Thymeleaf)

Để tùy chỉnh trang đăng nhập và đăng xuất, bạn cần tạo các trang HTML tương ứng và cấu hình chúng trong lớp bảo mật.

Ví dụ trang login với Thymeleaf (src/main/resources/templates/login.html):

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Login</title>
</head>
<body>
    <h1>Login</h1>
    <form th:action="@{/login}" method="post">
        <div>
            <label>Username:</label>
            <input type="text" name="username"/>
        </div>
        <div>
            <label>Password:</label>
            <input type="password" name="password"/>
        </div>
        <div>
            <button type="submit">Login</button>
        </div>
    </form>
</body>
</html>

Ví dụ trang logout với Thymeleaf (src/main/resources/templates/logout.html):

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Logout</title>
</head>
<body>
    <h1>You have been logged out</h1>
    <a th:href="@{/login}">Login again</a>
</body>
</html>

4. Tích hợp xác thực form-based với cơ sở dữ liệu

Sử dụng JdbcUserDetailsManager để xác thực người dùng

JdbcUserDetailsManager là một lớp cung cấp việc quản lý người dùng và quyền hạn từ cơ sở dữ liệu bằng JDBC. Để sử dụng JdbcUserDetailsManager, bạn cần thực hiện các bước sau:

  1. Cấu hình DataSource để kết nối với cơ sở dữ liệu.

  2. Tạo các bảng người dùng và quyền hạn trong cơ sở dữ liệu.

  3. Cấu hình JdbcUserDetailsManager trong Spring Security.

Ví dụ cấu hình JdbcUserDetailsManager:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.JdbcUserDetailsManager;

import javax.sql.DataSource;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private DataSource dataSource;

    @Bean
    public UserDetailsService userDetailsService() {
        return new JdbcUserDetailsManager(dataSource);
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.jdbcAuthentication().dataSource(dataSource);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/public/**").permitAll()
                .anyRequest().authenticated()
                .and()
            .formLogin()
                .loginPage("/login")
                .permitAll()
                .and()
            .logout()
                .permitAll();
    }
}
Ví dụ thực tế về tích hợp

Bước 1: Tạo các bảng trong cơ sở dữ liệu:

CREATE TABLE users (
    username VARCHAR(50) NOT NULL PRIMARY KEY,
    password VARCHAR(100) NOT NULL,
    enabled BOOLEAN NOT NULL
);

CREATE TABLE authorities (
    username VARCHAR(50) NOT NULL,
    authority VARCHAR(50) NOT NULL,
    FOREIGN KEY (username) REFERENCES users (username)
);

Bước 2: Thêm người dùng và quyền hạn vào cơ sở dữ liệu:

INSERT INTO users (username, password, enabled) VALUES ('user', '{noop}password', true);
INSERT INTO users (username, password, enabled) VALUES ('admin', '{noop}admin', true);

INSERT INTO authorities (username, authority) VALUES ('user', 'ROLE_USER');
INSERT INTO authorities (username, authority) VALUES ('admin', 'ROLE_ADMIN');

5. Triển khai Remember Me trong form-based Authentication

Khái niệm và cấu hình Remember Me

"Remember Me" là một tính năng cho phép người dùng giữ trạng thái đăng nhập ngay cả khi họ đóng trình duyệt. Điều này được thực hiện bằng cách sử dụng cookie lưu trữ thông tin xác thực.

Ví dụ cấu hình Remember Me:

import org.springframework

.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/public/**").permitAll()
                .anyRequest().authenticated()
                .and()
            .formLogin()
                .loginPage("/login")
                .permitAll()
                .and()
            .logout()
                .permitAll()
                .and()
            .rememberMe()
                .key("uniqueAndSecret");
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
            .withUser("user").password("{noop}password").roles("USER")
            .and()
            .withUser("admin").password("{noop}admin").roles("ADMIN");
    }
}
Ví dụ thực tế

Trong ví dụ trên, cấu hình Remember Me được bật với một khóa bảo mật duy nhất. Khi người dùng chọn tùy chọn "Remember Me" trên trang đăng nhập, một cookie sẽ được lưu trữ trên trình duyệt của họ để giữ trạng thái đăng nhập.

6. Xử lý lỗi xác thực và thông báo lỗi tùy chỉnh

Cách xử lý và hiển thị thông báo lỗi xác thực

Khi người dùng nhập thông tin đăng nhập không đúng, cần cung cấp thông báo lỗi để họ biết lý do không thể đăng nhập. Spring Security cung cấp các cơ chế để xử lý và hiển thị thông báo lỗi này.

Ví dụ tùy chỉnh thông báo lỗi trên trang login với Thymeleaf:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Login</title>
</head>
<body>
    <h1>Login</h1>
    <form th:action="@{/login}" method="post">
        <div>
            <label>Username:</label>
            <input type="text" name="username"/>
        </div>
        <div>
            <label>Password:</label>
            <input type="password" name="password"/>
        </div>
        <div>
            <button type="submit">Login</button>
        </div>
        <div th:if="${param.error}">
            <p style="color:red;">Invalid username or password</p>
        </div>
        <div th:if="${param.logout}">
            <p style="color:green;">You have been logged out successfully</p>
        </div>
    </form>
</body>
</html>
Tùy chỉnh các thông báo lỗi

Bạn có thể tùy chỉnh các thông báo lỗi bằng cách cấu hình AuthenticationFailureHandler để chuyển hướng người dùng đến trang lỗi tùy chỉnh.

Ví dụ cấu hình AuthenticationFailureHandler:

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/public/**").permitAll()
                .anyRequest().authenticated()
                .and()
            .formLogin()
                .loginPage("/login")
                .failureHandler(authenticationFailureHandler())
                .permitAll()
                .and()
            .logout()
                .permitAll();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
            .withUser("user").password("{noop}password").roles("USER")
            .and()
            .withUser("admin").password("{noop}admin").roles("ADMIN");
    }

    public AuthenticationFailureHandler authenticationFailureHandler() {
        return new SimpleUrlAuthenticationFailureHandler("/login?error=true");
    }
}

7. Kết luận

Tóm tắt lại các điểm chính
  • Form-based Authentication: Cung cấp giao diện thân thiện cho người dùng, dễ tùy chỉnh và tích hợp.

  • HTTP Basic Authentication: Đơn giản và dễ triển khai, phù hợp cho các dịch vụ web và API.

  • Cấu hình Remember Me: Giúp duy trì trạng thái đăng nhập ngay cả khi người dùng đóng trình duyệt.

  • Xử lý lỗi xác thực: Hiển thị thông báo lỗi tùy chỉnh để cải thiện trải nghiệm người dùng.

  • Tích hợp cơ sở dữ liệu: Sử dụng JdbcUserDetailsManager để quản lý xác thực từ cơ sở dữ liệu.

Các tài liệu tham khảo để học thêm

Bài tiếp theo sẽ đi sâu vào các khái niệm và cách triển khai OAuth2 và JWT trong Spring Security, với các ví dụ chi tiết về cấu hình và sử dụng.

20 Câu Hỏi Khái Quát Lại Kiến Thức về Xác Thực Cơ Bản trong Spring Security

  1. Form-based Authentication là gì?

    • Là phương thức xác thực sử dụng một biểu mẫu (form) đăng nhập để thu thập thông tin đăng nhập từ người dùng.
  2. HTTP Basic Authentication là gì?

    • Là phương thức xác thực đơn giản, gửi thông tin đăng nhập qua tiêu đề HTTP bằng cách mã hóa Base64.
  3. Lợi ích của form-based Authentication là gì?

    • Cung cấp giao diện thân thiện và dễ dàng tùy chỉnh cho người dùng.
  4. Lợi ích của HTTP Basic Authentication là gì?

    • Đơn giản và dễ triển khai, phù hợp cho các dịch vụ web và API.
  5. Cách cấu hình HTTP Basic Authentication trong Spring Security?

    • Sử dụng phương thức http.httpBasic() trong lớp cấu hình bảo mật.
  6. Làm thế nào để tạo lớp cấu hình bảo mật trong Spring Security?

    • Kế thừa WebSecurityConfigurerAdapter và ghi đè các phương thức cấu hình.
  7. Làm thế nào để cấu hình form-based login trong Spring Security?

    • Sử dụng phương thức http.formLogin() trong lớp cấu hình bảo mật.
  8. Làm thế nào để tùy chỉnh trang login sử dụng Thymeleaf?

    • Tạo trang HTML với form đăng nhập và cấu hình loginPage trong formLogin.
  9. JdbcUserDetailsManager là gì?

    • Là lớp cung cấp việc quản lý người dùng và quyền hạn từ cơ sở dữ liệu bằng JDBC.
  10. Làm thế nào để sử dụng JdbcUserDetailsManager trong Spring Security?

    • Cấu hình DataSource và đăng ký JdbcUserDetailsManager trong lớp cấu hình bảo mật.
  11. Các bảng cơ sở dữ liệu cần thiết cho JdbcUserDetailsManager là gì?

    • Bảng users và bảng authorities.
  12. Remember Me là gì trong Spring Security?

    • Là tính năng cho phép người dùng giữ trạng thái đăng nhập ngay cả khi đóng trình duyệt.
  13. Cách cấu hình Remember Me trong Spring Security?

    • Sử dụng phương thức http.rememberMe().key("uniqueAndSecret").
  14. Làm thế nào để hiển thị thông báo lỗi khi xác thực thất bại?

    • Sử dụng th:if="${param.error}" trong trang login với Thymeleaf.
  15. AuthenticationFailureHandler là gì?

    • Là một giao diện xử lý khi xác thực thất bại trong Spring Security.
  16. Làm thế nào để tùy chỉnh thông báo lỗi khi xác thực thất bại?

    • Sử dụng SimpleUrlAuthenticationFailureHandler để chuyển hướng đến trang lỗi tùy chỉnh.
  17. Lợi ích của việc sử dụng Remember Me là gì?

    • Giúp cải thiện trải nghiệm người dùng bằng cách duy trì trạng thái đăng nhập lâu dài.
  18. Làm thế nào để tích hợp xác thực form-based với cơ sở dữ liệu?

    • Sử dụng JdbcUserDetailsManager và cấu hình các bảng usersauthorities.
  19. Lợi ích của HTTP Basic Authentication là gì?

    • Đơn giản và không yêu cầu giao diện đăng nhập tùy chỉnh.
  20. Tại sao cần xử lý lỗi xác thực và hiển thị thông báo lỗi tùy chỉnh?

    • Cải thiện trải nghiệm người dùng và cung cấp thông tin hữu ích khi xác thực thất bại.

More from this blog

hoangkim

366 posts