Trong phần 1 của series https://viblo.asia/p/phan-1-spring-boot-30-va-spring-security-60-GAWVpdBYV05 chúng ta đã hoàn thành bước config cho ứng dụng. Ở bài viết này, chúng ta sẽ tiến hành phân quyền user cho website.(Bài viết này khá ngắn, tuy nhiên mọi ngưòi nên đọc kỹ để hiểu được lý do tại sao lại config như vậy, vì có thể viết nhầm làm chương trình không chạy được mà không biết lý do)
Ở bài viết trước cho dù đăng nhập với tài khoản ADMIN hoặc USER thì đều có thể xem được tất cả các api yêu cầu xác thực. Tuy nhiên trong bài toán thực tế, chúng ta sẽ cần kiểm tra quyền của user để xử lý một số nghiệp vụ nhất định, ví dụ như thêm sửa xóa các user trong hệ thống.
1. Đặt ra vấn đề
Quay trở lại với Project của bài trước
Ở đây chúng ta có 3 endpoints, với endpoint "customer/all" chỉ tài khoản có quyền ADMIN mới xem được, với endpoint "customer/{id}" chỉ tài khoản có quyền USER mới xem được.
2. Cách xử lý
Để có thể phân quyền trong project, Spring boot cung cấp cho chúng ta một annotation có tên là @PreAuthorize. Để có thể sử dụng, trước tiên chúng ta cần khai báo annotation @EnableMethodSecurity(có nhiệm vụ Enables Spring Security Method Security, mọi ngưòi có thể xem definition của annotation để hiểu rõ hơn) vào bất kỳ file nào có annotation @Configuration, ở trong project này là SecurityConfig,
Mình sẽ để link definition của @PreAuthorize ở đây để m.n có thể tìm hiểu thêm: https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/access/prepost/PreAuthorize.html, https://www.appsdeveloperblog.com/spring-security-preauthorize-annotation-example/
Với cách này, chúng ta chỉ cần thêm annotation vào mỗi Request Mapping và define role được quyền truy cập vào api
Lưu ý: Ở trong SecurityConfig có khai báo Bean userDetailsService như dưói đây:
@Bean public UserDetailsService userDetailsService(PasswordEncoder encoder) { UserDetails admin = User.withUsername("hach") .password(encoder.encode("hacheery")) .roles("ADMIN") .build(); UserDetails user = User.withUsername("user") .password(encoder.encode("pwd1")) .roles("USER") .build(); return new InMemoryUserDetailsManager(admin, user); }
Khi trỏ vào roles("ADMIN") mọi ngưòi sẽ thấy đoạn code define của roles như hình dưói
Ở dòng 416, khi chúng ta define role ADMIN, Springboot sẽ tự động thêm prefix "ROLE_" nên role ADMIN sẽ trở thành ROLE_ADMIN. Cho nên chúng ta cần khai báo @PreAuthorize("hasAuthority('ROLE_ADMIN')") thay vì @PreAuthorize("hasAuthority('ADMIN')")
Link source code: https://github.com/hachnv8/spring-security
Ở bài viết này, chúng ta đã cùng nhau phân quyền cho các endpoints. Trong bài viết tiếp theo, thay vì hard code user detail, chúng ta sẽ thực hiện các bước để lưu cũng như lấy dữ liệu user detail từ database. Nếu có vấn đề gì thắc mắc mọi người có thể cmt ở dưới ạ