การออกแบบระบบสิทธิ์ (Authorization) ที่แข็งแกร่งเป็นหัวใจสำคัญของแอปพลิเคชันระดับองค์กร ในบริบทของ Spring Boot และ Spring Security การจัดการสิทธิ์ (Role-Based Access Control: RBAC) จำเป็นต้องมีการสร้าง Entity Model ที่มีความสัมพันธ์ซับซ้อน โดยเฉพาะการใช้รูปแบบ Many-to-Many เพื่อเชื่อมโยง Role และ Permission เข้าด้วยกัน
บทความนี้จะเจาะลึกการสร้างโครงสร้าง Entity สำหรับ Role และ Permission โดยเน้นการใช้ JPA (Java Persistence API) ร่วมกับฐานข้อมูล PostgreSQL เพื่อให้ได้ระบบสิทธิ์ที่ยืดหยุ่นและขยายได้ในอนาคต
🏗️ หลักการออกแบบ Entity สำหรับ RBAC
โครงสร้างความสัมพันธ์ที่เหมาะสมที่สุดคือ:
- User มีความสัมพันธ์กับ Role (Many-to-Many)
- Role มีความสัมพันธ์กับ Permission (Many-to-Many)
ความสัมพันธ์แบบ Many-to-Many นี้จะถูกจัดการโดย JPA โดยการสร้างตาราง Join Table อัตโนมัติ (เช่น role_has_permissions) ซึ่งเป็นแนวทางปฏิบัติที่ดีที่สุดในการทำ Flyway Migration
🛡️ 1. Permission Entity: การกำหนดสิทธิ์ย่อย
Permission Entity ทำหน้าที่เก็บสิทธิ์ย่อย ๆ ที่เป็น atomic unit เช่น post-create, user-delete หรือ dashboard-view
ไฟล์: src/main/java/com/example/demo/entity/Permission.java
Java
package com.example.demo.entity; import jakarta.persistence.*; import lombok.Getter; import lombok.Setter; import java.util.Set; @Entity @Table (name = "permissions") @Getter @Setter public class Permission { @Id @GeneratedValue (strategy = GenerationType.IDENTITY) private Long id; @Column (unique = true, nullable = false) private String name; // ตัวอย่าง: "post-create" @Column (name = "guard_name") private String guardName = "web"; @ManyToMany (mappedBy = "permissions") private Set<Role> roles; }
👑 2. Role Entity: การรวมกลุ่มสิทธิ์
Role Entity ทำหน้าที่รวมกลุ่มของ Permission หลาย ๆ ตัวเข้าด้วยกัน และมีความสัมพันธ์กับ User ผ่านตาราง Join Table
ไฟล์: src/main/java/com/example/demo/entity/Role.java
Java
package com.example.demo.entity; import jakarta.persistence.*; import lombok.Getter; import lombok.Setter; import java.util.Set; @Entity @Table (name = "roles") @Getter @Setter public class Role { @Id @GeneratedValue (strategy = GenerationType.IDENTITY) private Long id; @Column (unique = true, nullable = false) private String name; // ตัวอย่าง: "ADMIN", "EDITOR" @ManyToMany (cascade = CascadeType.ALL, fetch = FetchType.EAGER) @JoinTable (name = "role_has_permissions", joinColumn = @JoinColumn(name = "role_id")) private Set<Permission> permissions; }
🔗 3. การจัดการความสัมพันธ์ (Mapping)
การใช้ `@JoinTable` ใน Role Entity จะสร้างตารางเชื่อมโยง role_has_permissions ในฐานข้อมูล PostgreSQL โดยอัตโนมัติ ซึ่งเป็นกลไกที่ทำให้ระบบสามารถจัดการความสัมพันธ์แบบ Many-to-Many ได้อย่างถูกต้องและมีประสิทธิภาพ
SQL
-- ตัวอย่าง SQL สำหรับการสร้างตาราง Role (PostgreSQL) -- CREATE TABLE roles ( id BIGSERIAL PRIMARY KEY, name VARCHAR(255) UNIQUE NOT NULL ); -- ตัวอย่าง SQL สำหรับการสร้างตาราง Join -- CREATE TABLE role_has_permissions ( role_id BIGINT REFERENCES roles(id), permission_id BIGINT REFERENCES permissions(id), PRIMARY KEY (role_id, permission_id) );
✅ บทสรุปและแนวทางปฏิบัติ
การกำหนด Entity Model ด้วย JPA ดังกล่าวข้างต้น ทำให้เราได้โครงสร้าง RBAC ที่สมบูรณ์แบบสำหรับการใช้งานกับ Spring Security และ PostgreSQL การใช้ Lombok ช่วยลด Boilerplate Code ได้อย่างมาก ในการนำไปใช้งานจริง ควรมีการใช้ Flyway หรือ Liquibase เพื่อจัดการ Schema Migration ของตารางเหล่านี้ เพื่อให้มั่นใจว่าโครงสร้างฐานข้อมูลมีความสอดคล้องกับโค้ด Java เสมอ