Phân quyền trong Spring Boot thường được thực hiện thông qua Spring Security, một framework mạnh mẽ cho việc bảo mật ứng dụng. Dưới đây là hướng dẫn chi tiết về cách cấu hình và sử dụng phân quyền trong một ứng dụng Spring Boot.

1. Cài đặt Spring Security

Để bắt đầu, bạn cần thêm dependency của Spring Security vào dự án của mình. Nếu bạn đang sử dụng Maven, thêm đoạn sau vào file pom.xml:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

Nếu bạn sử dụng Gradle, thêm vào file build.gradle:

implementation 'org.springframework.boot:spring-boot-starter-security'

2. Cấu hình Security

Tạo một class cấu hình cho Spring Security. Class này sẽ mở rộng WebSecurityConfigurerAdapter và ghi đè các phương thức cần thiết.

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/public/**").permitAll() // Cho phép truy cập không cần xác thực
                .antMatchers("/admin/**").hasRole("ADMIN") // Chỉ cho phép người dùng có vai trò ADMIN
                .anyRequest().authenticated() // Tất cả các yêu cầu khác cần phải xác thực
                .and()
            .formLogin() // Sử dụng form đăng nhập
                .permitAll()
                .and()
            .logout()
                .permitAll();
    }
}

3. Tạo User và Role

Bạn cần tạo người dùng và vai trò để phân quyền. Dưới đây là một ví dụ đơn giản về cách tạo một UserDetailsService:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;

@Service
public class CustomUserDetailsService implements UserDetailsService {

    private Map<String, User> users = new HashMap<>();

    @Autowired
    private PasswordEncoder passwordEncoder;

    public CustomUserDetailsService() {
        // Tạo một số người dùng giả lập
        users.put("admin", new User("admin", passwordEncoder.encode("admin123"), "ROLE_ADMIN"));
        users.put("user", new User("user", passwordEncoder.encode("user123"), "ROLE_USER"));
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = users.get(username);
        if (user == null) {
            throw new UsernameNotFoundException("User not found");
        }
        return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), user.getAuthorities());
    }
}

Định nghĩa lớp User

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;

import java.util.Collection;
import java.util.Collections;

public class User {
    private String username;
    private String password;
    private String role;

    public User(String username, String password, String role) {
        this.username = username;
        this.password = password;
        this.role = role;
    }

    public String getUsername() {
        return username;
    }

    public String getPassword() {
        return password;
    }

    public Collection<? extends GrantedAuthority> getAuthorities() {
        return Collections.singletonList(new SimpleGrantedAuthority(role));
    }
}

4. Sử dụng Annotation để Phân Quyền

Bạn có thể sử dụng các annotation như @PreAuthorize hoặc @Secured trên các phương thức trong controller để phân quyền chi tiết hơn.

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyController {

    @GetMapping("/public")
    public String publicEndpoint() {
        return "Đây là trang công khai.";
    }

    @GetMapping("/admin")
    @PreAuthorize("hasRole('ADMIN')")
    public String adminEndpoint() {
        return "Chỉ dành cho quản trị viên.";
    }

    @GetMapping("/user")
    @PreAuthorize("hasRole('USER')")
    public String userEndpoint() {
        return "Chỉ dành cho người dùng.";
    }
}

5. Cấu hình Mã hóa Mật khẩu

Để mã hóa mật khẩu, bạn cần thêm một bean cho PasswordEncoder. Thêm vào class cấu hình của bạn:

import org.springframework.context.annotation.Bean;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

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

6. Chạy ứng dụng

Bây giờ bạn có thể chạy ứng dụng và kiểm tra các điểm cuối (endpoint) đã được bảo mật. Bạn có thể sử dụng một công cụ như Postman để gửi yêu cầu đến các endpoint với thông tin đăng nhập khác nhau để xem phân quyền hoạt động như thế nào.

Kết luận

Phân quyền trong Spring Boot với Spring Security rất linh hoạt và mạnh mẽ. Bạn có thể dễ dàng cấu hình quyền truy cập cho từng endpoint, cũng như sử dụng annotation để kiểm soát quyền truy cập cho từng phương thức. Hãy chắc chắn rằng bạn đã cài đặt đúng các dependency và cấu hình để có được trải nghiệm tốt nhất với bảo mật trong ứng dụng của mình.