2013-11-02 12 views
6

Tôi đang sử dụng máy chủ GlassFish 4.0, trong đó tôi đã gán các quyền/vai trò khác nhau cho những người dùng khác nhau.Làm cách nào để mỗi người dùng truy cập tài nguyên tại một vị trí cụ thể theo quyền hạn/vai trò của họ trong JAAS?

Người dùng có thể có nhiều quyền/vai trò. Ví dụ: người dùng quản trị có thể được liên kết với ROLE_ADMIN (để thực hiện các tác vụ quản trị) và ROLE_USER (để thực hiện các tác vụ với tư cách người dùng đã đăng ký).

Trong số web.xml, cấu hình này được định cấu hình như sau.

<security-constraint> 
    <display-name>AdminConstraint</display-name> 
    <web-resource-collection> 
     <web-resource-name>ROLE_ADMIN</web-resource-name> 
     <description/> 
     <url-pattern>/admin_side/*</url-pattern> 
    </web-resource-collection> 
    <auth-constraint> 
     <description/> 
     <role-name>ROLE_ADMIN</role-name> 
    </auth-constraint> 
    <user-data-constraint> 
     <description/> 
     <transport-guarantee>CONFIDENTIAL</transport-guarantee> 
    </user-data-constraint> 
</security-constraint> 

<security-constraint> 
    <display-name>UserConstraint</display-name> 
    <web-resource-collection> 
     <web-resource-name>ROLE_USER</web-resource-name> 
     <description/> 
     <url-pattern>/user_side/*</url-pattern> 
    </web-resource-collection> 
    <auth-constraint> 
     <description/> 
     <role-name>ROLE_USER</role-name> 
    </auth-constraint> 
    <user-data-constraint> 
     <description/> 
     <transport-guarantee>CONFIDENTIAL</transport-guarantee> 
    </user-data-constraint> 
</security-constraint> 

<login-config> 
    <!--<auth-method>DIGEST</auth-method>--> 
    <auth-method>FORM</auth-method> 
    <realm-name>projectRealm</realm-name> 
    <form-login-config> 
     <form-login-page>/utility/Login.jsf</form-login-page> 
     <form-error-page>/utility/ErrorPage.jsf</form-error-page> 
    </form-login-config> 
</login-config> 

<security-role> 
    <description/> 
    <role-name>ROLE_ADMIN</role-name> 
</security-role> 

<security-role> 
    <description/> 
    <role-name>ROLE_USER</role-name> 
</security-role> 

Điều này chỉ hoạt động tốt.


Có hai mẫu URL /admin_side/*/user_side/*. Quản trị viên có hai vai trò ROLE_ADMINROLE_USER.

Khi quản trị viên đăng nhập bằng quyền hạn ROLE_USER, chỉ cần truy cập chỉ tài nguyên ở số /user_side/*. Tài nguyên nằm ở /admin_side/* không được phép truy cập vì quản trị viên được đăng nhập với tư cách là người dùng đã đăng ký và không phải là quản trị viên.

Cho đến bây giờ điều xảy ra trong trường hợp của tôi là khi quản trị viên đăng nhập bằng bất kỳ cơ quan nào, tài nguyên ở cả hai vị trí đều có thể truy cập hoàn toàn bất hợp pháp. Đó là bởi vì hệ thống có thể định vị cả chính quyền cho người dùng cụ thể đó.

Làm cách nào để mỗi người dùng truy cập tài nguyên tại một vị trí cụ thể theo quyền hạn/vai trò của họ?


Bộ lọc xác thực:

@WebFilter(filterName = "SecurityCheck", urlPatterns = {"/jass/*"}) 
public final class SecurityCheck implements Filter 
{ 
    private FilterConfig filterConfig = null; 

    @Resource(mappedName="jms/destinationFactory") 
    private ConnectionFactory connectionFactory; 
    @Resource(mappedName="jms/destination") 
    private Queue queue; 
    @EJB 
    private final UserBeanLocal userService=null; 

    public SecurityCheck() {} 

    private void sendJMSMessageToDestination(String message) throws JMSException 
    { 
     Connection connection = null; 
     Session session = null; 

     try 
     { 
      connection = connectionFactory.createConnection(); 
      session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); 
      MessageProducer messageProducer = session.createProducer(queue); 
      TextMessage textMessage = session.createTextMessage(); 
      textMessage.setText(message); 
      messageProducer.send(textMessage); 
     } 
     finally 
     { 
      if(session!=null){session.close();} 
      if(connection!=null){connection.close();} 
     } 
    } 

    private void doBeforeProcessing(ServletRequest request, ServletResponse response) throws IOException, ServletException 
    { 
     HttpServletRequest httpServletRequest=(HttpServletRequest)request; 
     httpServletRequest.login(httpServletRequest.getParameter("userName"), httpServletRequest.getParameter("password")); 
    } 

    private void doAfterProcessing(ServletRequest request, ServletResponse response) throws IOException, ServletException, JMSException 
    { 
     HttpServletRequest httpServletRequest=(HttpServletRequest)request; 
     HttpServletResponse httpServletResponse=(HttpServletResponse)response; 
     ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext(); 
     Map<String, Object> sessionMap = externalContext.getSessionMap(); 

     if(httpServletRequest.isUserInRole("ROLE_USER")) 
     { 
      sendJMSMessageToDestination(httpServletRequest.getLocalName()); 
      UserTable userTable = userService.setLastLogin(httpServletRequest.getParameter("userName")); 
      userTable.setPassword(null); 
      sessionMap.put("userName", userTable!=null?userTable.getFirstName():"Unknown"); 
      sessionMap.put("user", userTable); 

      httpServletResponse.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); 
      httpServletResponse.setHeader("Pragma", "no-cache"); 
      httpServletResponse.setDateHeader("Expires", 0); 
      httpServletResponse.sendRedirect("../user_side/Home.jsf"); 
     } 
     else if(httpServletRequest.isUserInRole("ROLE_ADMIN")) 
     { 
      sendJMSMessageToDestination(httpServletRequest.getLocalName()); 
      UserTable userTable = userService.setLastLogin(httpServletRequest.getParameter("userName")); 
      userTable.setPassword(null); 
      sessionMap.put("adminName", userTable!=null?userTable.getFirstName():"Unknown"); 
      sessionMap.put("user", userTable); 

      httpServletResponse.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); 
      httpServletResponse.setHeader("Pragma", "no-cache"); 
      httpServletResponse.setDateHeader("Expires", 0); 
      httpServletResponse.sendRedirect("../admin_side/Home.jsf"); 
     } 
    } 

    @Override 
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException 
    { 
     try 
     { 
      doBeforeProcessing(request, response); 
     } 
     catch (Exception e) 
     { 
      HttpServletResponse httpServletResponse=(HttpServletResponse)response; 
      //FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Error", "Incorrect user name and/or password. Access denied.")); 
      httpServletResponse.sendRedirect("../utility/Login.jsf"); 
      return; 
     } 

     chain.doFilter(request, response); 

     try 
     { 
      doAfterProcessing(request, response); 
     } 
     catch (JMSException ex) 
     { 
      Logger.getLogger(SecurityCheck.class.getName()).log(Level.SEVERE, null, ex); 
     } 
    } 

    //The rest of the filter. 
} 

Nếu bạn cần phải nhìn thấy những thứ khác trong ứng dụng của tôi sau đó, xin vui lòng cho tôi biết.

+0

Bạn đăng nhập vào quản trị viên với tư cách người dùng đã đăng ký chính xác như thế nào? Nếu một người dùng cụ thể có nhiều vai trò, thì thực sự không có cách nào để đăng nhập chỉ bằng một trong những vai trò đó. Vì vậy, toàn bộ câu hỏi là khó hiểu. – BalusC

+0

Đây là bộ lọc xác thực người dùng. Bộ lọc được ánh xạ tới URL patter - '/ jass/*' (đã nhập nhầm, phải là '/ jaas/*'). Nó chỉ ra một thư mục trong đó chỉ có một trang - 'temp.jsp', nơi yêu cầu được gửi đi, khi nhấn nút đăng nhập trên trang JSF (thông qua đậu được quản lý JSF tương ứng của nó). Không có cách nào để đăng nhập một lần với tư cách quản trị viên và một lần với tư cách là người dùng sử dụng cùng một id/mật khẩu? Tôi cũng cảm thấy như vậy nhưng nghĩ rằng các container có thể hỗ trợ một số cơ chế để làm điều này. Tôi nhìn vào một số hướng dẫn nhưng không tìm thấy gì về nó. – Tiny

Trả lời

1

Dường như bạn nghĩ rằng khi người dùng có nhiều vai trò, thì người dùng này chỉ có thể đăng nhập bằng một trong những vai trò đó cùng một lúc. Đây không phải là sự thật. Người dùng không đăng nhập trên cơ sở mỗi vai trò. Người dùng đăng nhập trên cơ sở mỗi người dùng. Nếu người dùng có nhiều vai trò, thì họ sẽ tất cả được sử dụng và áp dụng trong toàn bộ phiên đăng nhập.

Thực tế, đó là không có thể cho phép người dùng chọn và chỉ sử dụng một trong các vai trò được chỉ định trong suốt phiên. Cho đến nay, có vẻ như quản trị viên của bạn không nên có số ROLE_USER ở vị trí đầu tiên. Nhưng điều này làm cho thế giới thực ít ý nghĩa. Vai trò không phải là "mở rộng" vai trò hiện tại. I E. ROLE_ADMIN không được sao chép cùng các hạn chế như ROLE_USER và sau đó thêm một số chi tiết khác. Không, nó chỉ nên đại diện chính xác rằng "một số chi tiết". Người dùng quản trị sau đó được chỉ định cả hai vai trò (bạn đã làm phần đó một cách chính xác).Nếu không, bạn kết thúc với kiểm tra trùng lặp trong suốt mã tại những nơi có thể được truy cập/sử dụng bởi cả người dùng và quản trị viên. Và sau đó tôi không nói về một vai trò thứ ba trên đây mà có thể yêu cầu kiểm tra ba trong mã. Bạn cần chỉnh sửa mã hiện tại trên tất cả các địa điểm.

Nếu bạn muốn chuyển đổi vai trò theo chương trình trong thời gian chạy, có thể vì bạn muốn có thể "xem trước" trang web dưới dạng người dùng thông thường (ví dụ: kiểm tra xem trang web trông như thế nào khi các phần/nút chỉ dành cho quản trị viên ẩn), sau đó về cơ bản có hai tùy chọn:

  1. Đặt một số cờ làm thuộc tính phiên hoặc có thể là tham số yêu cầu và kiểm tra mã đó. Ví dụ.

    <h:form> 
        <h:selectBooleanCheckbox value="#{sessionScope.preview}"> 
         <f:ajax render="@all" /> 
        </h:selectBooleanCheckbox> 
    </h:form> 
    

    (lưu ý: mã này là như-là, #{sessionScope} là một EL biến ngầm ám chỉ ExternalContext#getSessionMap(), không đậu thêm sự ủng hộ cần thiết)

    Và sau đó trong tamplate thạc sĩ:

    <c:set var="userIsAdmin" value="#{request.isUserInRole('ROLE_ADMIN') and not preview}" scope="request" /> 
    

    Và trong chế độ xem mục tiêu chứa một số công cụ quản trị cụ thể:

    <h:commandButton value="Some awesome admin button" rendered="#{userIsAdmin}" /> 
    

  2. Thực hiện đăng nhập có lập trình dưới dạng người dùng thông thường. Bạn có thể sử dụng HttpServletRequest#login() để kích hoạt xác thực quản lý vùng chứa được lập trình. Bằng cách này, quản trị viên có thể "mạo danh" một người dùng khác và duyệt trang web như thể anh ta đã đăng nhập với tư cách người dùng cụ thể. Ví dụ. trong một phiên phạm vi đậu:

    public void runAs(User user) { 
        // ... 
        try { 
         request.login(user.getUsername(), user.getPassword()); 
         originalUser = currentUser; 
         currentUser = user; 
         // ... 
        } catch (ServletException e) { 
         // ... 
        } 
    } 
    
    public void releaseRunAs() { 
        // ... 
        try { 
         request.login(originalUser.getUsername(), originalUser.getPassword()); 
         currentUser = originalUser; 
         // ... 
        } catch (ServletException e) { 
         // ... 
        } 
    } 
    

    Bạn thậm chí có thể mở rộng bằng cách giữ tất cả người dùng trước đó trong hàng đợi LILO (cuối cùng, cuối cùng) trong phạm vi phiên. Hầu hết các khung bảo mật như Apache Shiro có builtin APIs cho việc này.

+0

Tôi hiện đang ở phương thức "* cho mỗi người dùng *" thay vì đi vào phức tạp một cách không cần thiết. Chủ yếu, tôi muốn biết liệu nó được hỗ trợ bởi container, ra khỏi hộp mà tôi đã hoàn toàn mệt mỏi của lật trở lại và ra các tài liệu Oracle :) Tôi bây giờ loại bỏ nghi ngờ lớn của tôi. Cảm ơn. – Tiny

1

Tôi nghĩ cách nhận hành vi bạn yêu cầu là rất cẩn thận với điều này, có thể thêm tài khoản quản trị khác thay thế và xóa ROLE_USER khỏi tài khoản đó.

+0

Trước khi đặt câu hỏi này, tôi cũng nghĩ rằng đây chỉ là câu trả lời cho câu hỏi này :). Tuy nhiên, chúng tôi không thể nói một người dùng có thể có nhiều quyền/vai trò vì người dùng yêu cầu phải có nhiều tài khoản tương ứng với nhiều quyền/vai trò. Mặc dù một người dùng có thể có nhiều tài khoản với các quyền/vai trò khác nhau, ** tất cả họ đều được xử lý như những người dùng khác nhau bởi hệ thống ** :). – Tiny

Các vấn đề liên quan