EJB3的宣告式安全,可以使用Annotation來宣告基於Role的授權,指明類別或哪些方法可以被哪些角色所存取。
您可以在類別上使用@DeclarRoles宣告有效的Role名稱,例如:
@Stateless
@DeclarRoles({"admin", "manager"})
public class HelloBeanImpl implements HelloBean {
....
}
如果您沒有宣告有效的Role名稱,則容器也會自動根據所設定的@RolesAllowed來建立,@RolesAllowed可以套用在類別或方法上,若套用在類別上,則該類別的所有方法都必須是指定的Role才可以存取,若套用在方法上,則該方法必須是指定的Role才可以存取,例如:
@Stateless
@DeclarRoles({"admin", "manager"})
public class HelloBeanImpl implements HelloBean {
@RolesAllowed("admin")
public void doAdmin() {
...
}
...
}
您也可以使用@PermitAll或@DenyAll來標註整個類別或方法,標註@PermitAll表示可以被任何Role使用呼叫,@DenyAll則是相反,表示任何Role都不得使用呼叫,在某些環境中,不適合呼叫某些方法或類別時,您就可以使用@DenyAll來設定,而不用直接修改程式碼。
您可以使用@RunAs標註類別或方法,在執行時A Role的方法中,若呼叫了某些B Role才能呼叫的方法,則可暫時以B Role來執行,例如:
@Stateless
@DeclarRoles({"admin", "manager"})
@RunAs("admin")
public class HelloBeanImpl implements HelloBean {
@RolesAllowed("admin")
public void doAdmin() {
...
} @RolesAllowed("admin")
public void doAdmin() {
...
}
...
...
@RolesAllowed("manager")
public void doManager() {
...
doAdmin(); // 需要 admin 的 Role 才能執行
...
}
...
}
manager的Role執行doManager(),由於其中執行了admin的Role才可以執行的方法,若沒有設定如上的@RunAs,則會發生錯誤。
Java EE的安全是基於JAAS(Java Authentication and
Authorization Service),若為Web應用程式,可以搭配Web容器的URL
Pattern為基礎的宣告安全設定,當使用者登入後,Web容器會將通過驗證的Principal傳遞給EJB容器,可以很簡單的完成驗證與EJB3上
的宣告授權。若不透過Web容器的宣告安全設定而想使用EJB3宣告授權,需要深入了解JAAS的內容,這已不在這個文件的說明範圍。
以下配合Web容器的 使用宣告式安全(Http Basic Authentication),讓Web容器為您作驗證,並在Servlet中呼叫EJB3的Bean,看看如何使用EJB3的宣告安全,首先是Bean的撰寫:
package onlyfun.caterpillar;
import javax.ejb.Remote;
@Remote public interface HelloBean { public String doHello(String message); public String doSecurity(String message); }
package onlyfun.caterpillar;
import javax.annotation.security.*; import javax.ejb.Stateless;
@Stateless public class HelloBeanImpl implements HelloBean { @RolesAllowed("foo") public String doSecurity(String message) { return message + "security processed...."; } public String doHello(String message) { return message + "processed...."; } }
其中doSecurity()必須是foo的Role才可以存取,其它方法則無限制,若您撰寫一個Servlet如下:
package onlyfun.caterpillar;
import java.io.*; import javax.servlet.*; import javax.servlet.http.*; import javax.ejb.EJB;
public class HelloServlet extends HttpServlet { @EJB private HelloBean hello; protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String method = request.getParameter("method"); if("security".equals(method)) { response.getWriter().println(hello.doSecurity("info....")); } else { response.getWriter().println(hello.doHello("hello....")); } }
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); }
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); }
public String getServletInfo() { return "Short description"; } }
這個Servlet使用Web的安全宣告加以保護,只能是foo或orz的Role才可以請求:
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <servlet> <servlet-name>HelloServlet</servlet-name> <servlet-class>onlyfun.caterpillar.HelloServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>HelloServlet</servlet-name> <url-pattern>/HelloServlet</url-pattern> </servlet-mapping> <security-role> <role-name>foo</role-name> </security-role> <security-role> <role-name>orz</role-name> </security-role> <security-constraint> <display-name>SecurityConstraint</display-name> <web-resource-collection> <web-resource-name>Secret Information</web-resource-name> <url-pattern>/HelloServlet</url-pattern> </web-resource-collection> <auth-constraint> <role-name>foo</role-name> <role-name>orz</role-name> </auth-constraint> </security-constraint> <login-config> <auth-method>BASIC</auth-method> <realm-name>file</realm-name> </login-config> </web-app>
若您的Glassfish上有caterpillar及justin使用者,群組分別設為fooGroup與orzGroup,而sun-web.xml的設定如下:
...
<security-role-mapping>
<role-name>foo</role-name>
<group-name>fooGroup</group-name>
</security-role-mapping>
<security-role-mapping>
<role-name>orz</role-name>
<group-name>orzGroup</group-name>
</security-role-mapping>
...
若您請求/HelloServlet,並指定method=security參數,當使用caterpillar登入時,才可以呼叫HelloBean的doSecurity(),若使用justin登入,雖可以通過驗證來請求,但因Role不正確,所以呼叫HelloBean的doSecurity()時,就會出現授權失敗的錯誤。
若不指定method=security參數,則呼叫的是HelloBean的doHello(),則無論登入的是caterpillar或justin,都可以正確執行。
|