• Hãy ủng hộ PhienBanMoi.Com bằng cách LIKE trang FANPAGE , GOOGLE+ dưới mỗi bài viết hoặc chia sẻ website nếu thấy hữu ích. Trân trọng cảm ơn!
  • [Thông Báo] Tuyển thành viên viết bài KIẾM TIỀN trên PhienBanMoi.Com


    Nhằm mục đích phát triển Phienbanmoi.com hơn nữa, có thêm các bài viết thông tin thực sự hữu ích từ những thành viên tích cực. BQT đã quyến định tạo ra cơ hội kiếm tiền từ các bài viết được đăng tải và chia sẻ trên diễn đàn

Hướng dẫn phân quyền động (dynamic) , bảo mật với Spring Security (phần 1)

No Nguyễn

Admin
Thành viên BQT
Tham gia
3/2/12
Bài viết
1,449
Thích
2,056
Nơi ở
Xuân Thủy - Cầu Giấy - Hà Nội
#1
Lời nói đầu
Spring Security cung cấp một hỗ trợ mạnh mẽ để bảo mật các ứng dụng dựa trên Spring nhưng nó thất bại theo một cách nào đó khi thiết kế bảo mật có thể cấu hình động, đặc biệt là về khả năng cấu hình động của truy cập các phương thức java. Làm thế nào chúng ta có thể khắc phục những hạn chế này?

Giới thiệu
Khi chúng tôi muốn bảo mật ứng dụng, chúng tôi phải xác định các chính sách truy cập cho các chức năng của nó và về cơ bản chúng tôi phải đối phó với hai mô hình chính mà chúng tôi có thể gọi là 'bảo mật dựa trên vai trò' và 'bảo mật dựa trên đối tượng' ('role-based' ,'object-based' )
Trong đó hoạt động đầu tiên bằng cách xác định vai trò bởi người dùng và giới hạn quyền truy cập của người dùng vào các chức năng hệ thống cụ thể ,
trong khi mô hình thứ hai tập trung vào các quyền được xác định trên các đối tượng miền duy nhất.

Sự phân đôi này cũng đúng với Spring Framework
Spring Security cung cấp cả hai mô hình này và cho mỗi mô hình cung cấp một giải pháp mạnh mẽ. Bảo mật dựa trên vai trò được triển khai bởi Spring Security authorization API và bảo mật dựa trên đối tượng bởi modul ACL.

Mỗi mô hình giải quyết một lĩnh vực cụ thể và có lẽ cả hai đều đáp ứng hầu hết các nhu cầu nhưng có một số hạn chế khi thiết kế các giải pháp tiên tiến hơn. Nếu chúng ta muốn, thì sao?
Ví dụ: Để tự động cấu hình authorization để thực thi phương thức? Trong Spring Security, chúng ta có thể bảo mật các phương thức bằng cách đặt chú thích (anotation) với biểu thức dựa trên vai trò (role), nhưng vai trò (role) là thứ được xác định và định cấu hình trước, không phải là động (dynamic) .

Một cách khác là sử dụng ACL để bảo mật một phương thức dựa trên các quyền mà đối tượng miền được truyền như một đối số , nhưng điều này không bao gồm tình huống trong đó chúng tôi chỉ muốn cho phép thực thi phương thức mà không tham chiếu đến các tham số của nó. Chắc chắn có nhiều cách tùy chỉnh các lớp Spring Security để khắc phục những hạn chế này, nhưng trong bài viết này, chúng tôi muốn chỉ ra một giải pháp khả thi khai thác chính mô hình bảo mật ACL để cung cấp một cơ sở duy nhất để bảo vệ toàn bộ ứng dụng theo cách năng động.
Nhưng trước tiên, hãy xem qua về cách các phương thức được bảo mật authorized và ACL dựa trên vai trò ‘role-based’ trong thực tế.

Bảo mật dựa trên vai trò - ‘role-based’
Vai trò trong Spring Security được thể hiện bằng một thể hiện của lớp GrantedAuthority. Một danh sách các đối tượng GrantedAuthority có thể được lưu trữ trên một đối tượng Authentication để thể hiện vai trò của người dùng được xác thực hiện tại. AuthenticationManager có trách nhiệm chèn GrantedAuthority vào đối tượng Authentication. Một AccessDecisionManager sẽ chịu trách nhiệm đưa ra quyết định ủy quyền dựa trên các câu lệnh được định cấu hình trong tệp cấu hình Spring xml hoặc dưới dạng biểu thức trong chú thích. Người ta có thể tự thực hiện AccessDecisionManager hoặc sử dụng một trong các triển khai Spring dựa trên biểu quyết của interface AccessDecisionVoter. Các phương thức có thể được bảo mật cả với cấu hình AOP hoặc theo cách đơn giản hơn bằng cách sử dụng các chú thích và biểu thức như sau :
Java:
@PreAuthorize("hasRole('ROLE_USER')")

public void method();
Bảo mật dựa trên đối tượng Secure objects (ACL)
ACL dựa vào API được hỗ trợ bởi các bảng trong cơ sở dữ liệu để xác định các quyền (như write, delete, admin ) trên các single object domain. Một cách phổ biến để bảo mật một đối tượng là sử dụng biểu thức hasPermission trong một chú thích như sau:

Java:
@PreAuthorize("hasPermission(#contact, 'admin')")
public void admin(Contact contact);
Trong ví dụ trên, việc thực thi quản trị viên chỉ được ủy quyền nếu tham số liên hệ hiện tại có quyền 'admin '.

Một giải pháp để thực hiện phương pháp phân quyền động

Spring dường như không cung cấp giải pháp vượt trội cho các phương thức bảo mật động, tức là đặt quyền để thực thi một phương thức nhanh chóng. Người ta có thể giới hạn quyền truy cập vào các phương thức bằng cách sử dụng vai trò hoặc xác định quy tắc cho phép truy cập trên các tham số phương thức bằng ACL. Vai trò là một cách khá tĩnh để xác định quy tắc truy cập, chúng phải được xác định trước và được phân loại theo khóa học, một vai trò không được nhắm trực tiếp đến một phương thức hoặc đối tượng duy nhất nhưng thể hiện một số quy tắc chung giới hạn quyền truy cập vào một số khu vực nhất định của ứng dụng . Mặt khác, ACL được sử dụng để bảo vệ các đối tượng đơn lẻ bằng các quyền, đó là các khái niệm rất chi tiết liên quan trực tiếp đến các đối tượng được bảo mật và không phải đối với một số hành vi ứng dụng chung. Một cách để khắc phục những hạn chế này là thực hiện một số tùy chỉnh API Spring Security class AccessDecisionManager. Tuy nhiên, ở giữa mô hình ACL Spring Security, đã có một cái gì đó có thể thực hiện được mánh khóe, có thể theo một cách đơn giản và gọn gàng hơn. Chìa khóa sẽ là thể hiện một vai trò không phải là một hành vi ứng dụng chung liên quan đến người dùng mà chỉ đơn giản là một tập các quyền. Chúng ta hãy nhớ lại ngắn gọn các thực thể chính liên quan đến thiết kế ACL:

  • Acl: nó đại diện cho một đối tượng, thông thường là một đối tượng miền bởi một ObjectIdentity và nó lưu trữ một tập hợp AccessControlEntries
  • AccessControlEntry(ACE): nó bao gồm a Permission, Sid và Acl.
  • Permission: Một quyền cho biết những gì có thể được thực hiện cho một đối tượng (như viết, đọc, quản trị viên) và nó được thực hiện bởi một mặt nạ bit bất biến cụ thể.
  • Sid: nó đại diện cho một Principa lhoặc GrantedAuthority.
  • ObjectIdentity: Mỗi đối tượng miền được thể hiện bên trong mô-đun ACL bởi một ObjectIdentity.

Các lớp này được duy trì cho cơ sở dữ liệu bằng các bảng sau:

  • ACL_SID nó lưu trữ các trường hợp Sid
  • ACL_CLASS mục đích của nó là xác định bất kỳ lớp đối tượng miền nào trong hệ thống.
  • ACL_OBJECT_IDENTITY lưu trữ thông tin cho từng phiên bản đối tượng miền duy nhất trong hệ thống, nó có liên quan đến các thể hiện Acl và chứa khóa ngoại đối với phiên bản ACL_CLASS đại diện cho loại đối tượng
  • ACL_ENTRY lưu trữ các trường hợp AccessControlEntry

Nếu chúng ta nghĩ rằng một Sid có thể đại diện cho cả một hiệu trưởng hoặc GranthedAuthority chúng ta đang đưa thẳng vào vấn đề: mô hình ACL cho chúng ta đã là một cách để thực hiện vai trò như là một tập các điều khoản, vì một ACE là một tập hợp Permission, Sid và Acl . Một tập hợp các ACE trong đó Sid đại diện cho một đơn GrantedAuthority có thể được xem chính xác như một vai trò được tạo thành từ một tập các quyền. Chúng tôi thậm chí có thể gán quyền trực tiếp cho người sử dụng, sử dụng Sid như một Principal thay vì một GrantedAuthority. Nhưng loại quyền nào chúng ta có thể liên kết với một phương pháp? Những gì chúng tôi muốn bảo mật là thực thi phương thức để chúng tôi có thể xác định một quyền tùy chỉnh và chúng tôi có thể gọi nó là 'thực thi', ví dụ. Sau đó chúng ta có thể biểu diễn một Acl thực thi phương thức, chính xác như là một trình bao bọc của một thể hiện của lớp java.lang.reflect.Method . Trình bao bọc là cần thiết để cung cấp một thuộc tính id bổ sung để xác định thể hiện thực thi phương thức cụ thể. ACL sau đó sẽ được cung cấp bộ ACE riêng với quyền 'thực thi' được liên kết với người dùng hoặc vai trò (nghĩa là với một Principal hoặc GrantedAuthority). Để bảo mật một phương thức sau đó, một chú thích tùy chỉnh có thể được triển khai, hãy gọi nó là SecureMethodExecute , như:



Java:
@Target (ElementType.METHOD)

@Retention (RetentionPolicy.RUNTIME)

@Secured ("ROLE_DUMMY")

@interface SecureMethodExecut {

}
Ở đây, khai báo chú thích SecureMethodExecute sử dụng chú thích @Secured của Spring Security như một chú thích meta để @SecureMethodExecut được Spring nhận ra như thể nó được @Secured với giá trị thuộc tính ROLE_DUMMY. Mục đích duy nhất của thuộc tính là ROL ROLE_DUMMY 'là để có được AccessDecisionManager mặc định cho mối quan hệ và nghĩ rằng @SecureMethodExecut là một chú thích @Secured thông thường.

Sau đó, các phương thức có thể được chú thích như thế này:

Java:
@SecureMethodExecut

public void methodName () {...}
Cuối cùng, việc triển khai cụ thể interface AccessDecisionVoter sẽ cung cấp logic truy cập. Sau đây là một ví dụ về method vote:

Java:
public int vote(Authentication authentication, Object object,

Collection attributes) {



if(object instanceof ReflectiveMethodInvocation){

   MethodInvocation methodInvocation = (MethodInvocation) object;

   if (methodInvocation.getMethod().getAnnotation(

    SecureMethodExecution.class) != null) {

    MethodWrapper methodWrapper = new MethodWrapper(methodInvocation.

       getMethod());

    boolean haspermission = permissionEvaluator.hasPermission(

           authentication,methodWrapper, CustomPermission.EXECUTE);

    if (!haspermission) {

     return ACCESS_DENIED;

    }

   }

}



return ACCESS_GRANTED;

}
Sử dụng mô hình này, giao diện người dùng có thể được xây dựng theo đó các trường hợp ACE có thể được tạo hoặc xóa ngay lập tức cho mọi phương thức cần được bảo mật (phương thức dịch vụ, thông thường), mà không cần cấu hình tĩnh và khởi động lại ứng dụng.

Kết luận
Cho rằng có thể có một số cách khác nhau để bảo mật động các phương thức trong Spring Security, tuy nhiên giải pháp ở trên phụ thuộc vào chính kiến trúc Spring Security và nó chỉ cần các tùy chỉnh nhỏ.

Tài liệu tham khảo
Tài liệu tham khảo Spring Security : http://docs.spring.io/spring-security/site/docs/3.0.x/reference/springsecurity.html
 

Bài xem nhiều