05 - Spring Boot Security

03/03/2025 - 4 phút

Follow  on Google News

Trong bài viết này, chúng ta sẽ tìm hiểu về Spring Boot Security, cách bảo mật ứng dụng với Spring Security.

1. Giới Thiệu

Bảo mật là một phần quan trọng trong bất kỳ ứng dụng web nào. Spring Boot Security cung cấp một giải pháp bảo mật mạnh mẽ và linh hoạt cho các ứng dụng Spring Boot. Với Spring Security, bạn có thể dễ dàng thiết lập xác thực (authentication)ủy quyền (authorization) cho ứng dụng của mình.

Trong bài viết này, chúng ta sẽ tìm hiểu cách sử dụng Spring Boot Security, cách cấu hình xác thực người dùng, và bảo vệ API bằng JWT (JSON Web Token).

2. Cách Cài Đặt Spring Boot Security

Spring Boot Security có thể được thêm vào dự án bằng cách thêm dependency sau vào pom.xml:

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

Sau khi thêm dependency này, Spring Security sẽ tự động cấu hình bảo mật mặc định, yêu cầu xác thực cho tất cả endpoint.

3. Bảo Mật Mặc Định Của Spring Boot Security

Mặc định, Spring Security sẽ:

  • Bảo vệ tất cả các endpoint.
  • Tạo một user mặc định với tên user và mật khẩu được sinh ngẫu nhiên (hiển thị trong log khi khởi động ứng dụng).

Ví dụ log khi chạy ứng dụng:

Using generated security password: 8d7a2a7c-bf63-4f1e-9e7f-97a9a7f58b60

Bạn có thể thay đổi thông tin đăng nhập mặc định trong application.properties:

spring.security.user.name=admin
spring.security.user.password=secret

Sau đó, khi truy cập localhost:8080, trình duyệt sẽ yêu cầu đăng nhập với thông tin trên.

4. Cấu Hình Xác Thực Người Dùng Tuỳ Chỉnh

4.1. Tạo Lớp Cấu Hình Security

Spring Security yêu cầu một Security Configuration để cấu hình cách xác thực và ủy quyền.

Ví dụ, chúng ta có thể tạo một lớp SecurityConfig.java để cấu hình xác thực dựa trên trong bộ nhớ (in-memory authentication):

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/admin").hasRole("ADMIN")
                .requestMatchers("/user").hasAnyRole("USER", "ADMIN")
                .anyRequest().authenticated()
            )
            .formLogin()
            .and()
            .httpBasic();
        return http.build();
    }

    @Bean
    public UserDetailsService userDetailsService() {
        UserDetails user = User.withDefaultPasswordEncoder()
            .username("user")
            .password("password")
            .roles("USER")
            .build();
        
        UserDetails admin = User.withDefaultPasswordEncoder()
            .username("admin")
            .password("admin")
            .roles("ADMIN")
            .build();
        
        return new InMemoryUserDetailsManager(user, admin);
    }
}

Trong cấu hình trên:

  • /admin chỉ dành cho người dùng có quyền ADMIN.
  • /user dành cho người dùng có quyền USER hoặc ADMIN.
  • HTTP Basic Authentication được kích hoạt.
  • Người dùng được khai báo trong bộ nhớ với vai trò (ROLE_USER, ROLE_ADMIN).

5. Sử Dụng JWT Để Xác Thực API

Mặc định, Spring Security sử dụng phiên làm việc (session) để lưu thông tin đăng nhập. Tuy nhiên, đối với ứng dụng REST API, JWT (JSON Web Token) là phương pháp phổ biến để xác thực.

5.1. Thêm Dependency Cho JWT

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.11.2</version>
</dependency>

5.2. Tạo Lớp JWT Util

Lớp này giúp tạo và xác thực JWT:

import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import org.springframework.stereotype.Component;
import java.security.Key;
import java.util.Date;

@Component
public class JwtUtil {
    private final String SECRET_KEY = "your_secret_key_your_secret_key";
    private final Key key = Keys.hmacShaKeyFor(SECRET_KEY.getBytes());

    public String generateToken(String username) {
        return Jwts.builder()
                .setSubject(username)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60))
                .signWith(key, SignatureAlgorithm.HS256)
                .compact();
    }

    public String extractUsername(String token) {
        return Jwts.parserBuilder().setSigningKey(key).build()
                .parseClaimsJws(token).getBody().getSubject();
    }
}

5.3. Tạo Bộ Lọc JWT

Lớp này giúp kiểm tra JWT trong mỗi request:

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;

@Component
public class JwtFilter extends OncePerRequestFilter {
    private final JwtUtil jwtUtil;

    public JwtFilter(JwtUtil jwtUtil) {
        this.jwtUtil = jwtUtil;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {
        String token = request.getHeader("Authorization");
        if (token != null && token.startsWith("Bearer ")) {
            token = token.substring(7);
            String username = jwtUtil.extractUsername(token);
            UserDetails userDetails = User.withUsername(username).password("").roles("USER").build();
            UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(authToken);
        }
        chain.doFilter(request, response);
    }
}

6. Kết Luận

Spring Boot Security giúp bạn bảo vệ ứng dụng dễ dàng với nhiều phương thức xác thực như session-based authenticationJWT authentication.

Tóm tắt các tính năng quan trọng:

  • Xác thực mặc định với user và password.
  • Cấu hình bảo mật tùy chỉnh với SecurityFilterChain.
  • Sử dụng JWT để xác thực API.
  • Bảo vệ tài nguyên theo vai trò với quyền ROLE_USER, ROLE_ADMIN.

👉 Trong bài viết tiếp theo, chúng ta sẽ tìm hiểu về Spring Boot Data JPA, cách làm việc với cơ sở dữ liệu một cách hiệu quả!