如果打算讓 Web 容器提供基本驗證的功能,則可以在 web.xml 中定義:
<login-config>
<auth-method>BASIC</auth-method>
</login-config>
接著要授予指定角色存取頁面的權限,所以要先定義角色。之前說過,目前不知道這個應用程式將部署到哪個伺服器上,所以也無法預測會有哪些使用者名稱與群組,所以在進行授權管理前,無法根據使用者名稱或群組來進行授權,而是根據角色。所以在授權之前,必須定義這個應用程式中,有哪些角色名稱。可以在 web.xml 中如下定義:
<security-role>
<description>Admin User</description>
<role-name>admin</role-name>
</security-role>
<security-role>
<description>Manager</description>
<role-name>manager</role-name>
</security-role>
在這邊定義 了admin 與 manager 兩個角色名稱。接著定義哪些 URL 可以被哪些角色以哪種 HTTP 方法存取。例如,設定 /admin 下所有頁面,無論使用哪個 HTTP 方法,都只能被 admin 角色存取:
<security-constraint>
<web-resource-collection>
<web-resource-name>Admin</web-resource-name>
<url-pattern>/admin/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
</auth-constraint>
</security-constraint>
如果有多個角色可以存取,則 <auth-constraint>
標籤中可以設置多個 <role-name>
標籤。在這邊看不到任何 HTTP 方法規範的定義,預設就是所有 HTTP 方法都受到此 <security-constraint>
定義的約束,只有指定的角色才能存取。
再來看另一個例子:
<security-constraint>
<web-resource-collection>
<web-resource-name>Manager</web-resource-name>
<url-pattern>/manager/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
<role-name>manager</role-name>
</auth-constraint>
</security-constraint>
在這個設定中,對於 /manager 下的所有頁面,根據 <http-method>
的設定,只有 admin 或 manager 才可以使用 GET
與 POST
方法進行存取。請留意這個語義,這表示,除了 GET
、POST
受約束外,其他 HTTP 方法是不受約束的,無論是否具備 admin 或 manager角色,都可以存取!
如果除了 GET
、POST
之外,其他方法都要受到約束,除了使用 <http-method>
逐一列出 HEAD
、PUT
等方法外,有個更方便的方式,就是使用 <http-method-omission>
:
<security-constraint>
<web-resource-collection>
<web-resource-name>Manager</web-resource-name>
<url-pattern>/manager/*</url-pattern>
<http-method-omission>GET</http-method-omission>
<http-method-omission>POST</http-method-omission>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
<role-name>manager</role-name>
</auth-constraint>
</security-constraint>
如果沒有設定 <auth-constraint>
標籤,或是 <auth-constraint>
標籤中設定 <role-name>*</role-name>
,表示任何角色都可以存取,在 Servlet 3.1 中,<role-name>**</role-name>
表示任一通過驗證的使用者。如果直接撰寫 <auth-constraint/>
,那就沒有任何角色可以存取了。
例如,除了 GET
、POST
之外,其他方法一律拒絕,可以這麼寫:
<security-constraint>
<web-resource-collection>
<web-resource-name>Manager</web-resource-name>
<url-pattern>/manager/*</url-pattern>
<http-method-omission>GET</http-method-omission>
<http-method-omission>POST</http-method-omission>
</web-resource-collection>
<auth-constraint/>
</security-constraint>
約束 GET
、POST
,然而拒絕其他 HTTP 方法,可以這麼撰寫:
<security-constraint>
<web-resource-collection>
<web-resource-name>Manager</web-resource-name>
<url-pattern>/manager/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
<role-name>manager</role-name>
</auth-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>Manager</web-resource-name>
<url-pattern>/manager/*</url-pattern>
<http-method-omission>GET</http-method-omission>
<http-method-omission>POST</http-method-omission>
</web-resource-collection>
<auth-constraint/>
</security-constraint>
在 Servlet 3.1 中,對於未被列入 <security-constraint>
的方法,定義為未涵蓋的 HTTP 方法(Uncovered Http Method),並有個 <deny-uncovered-http-methods/>
可以拒絕未涵蓋的 HTTP 方法,試圖存取的話,會傳回 403(SC_FORBIDDEN),因此,上面的例子,在 Servlet 3.1 中可以寫為:
<deny-uncovered-http-methods/>
<security-constraint>
<web-resource-collection>
<web-resource-name>Manager</web-resource-name>
<url-pattern>/manager/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
<role-name>manager</role-name>
</auth-constraint>
</security-constraint>
以下是個完整的設定範例:
<?xml version="1.0" encoding="UTF-8"?>
<web-app
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0">
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<security-constraint>
<web-resource-collection>
<web-resource-name>Admin</web-resource-name>
<url-pattern>/admin/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
</auth-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>Manager</web-resource-name>
<url-pattern>/manager/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
<role-name>manager</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
</login-config>
<security-role>
<role-name>admin</role-name>
</security-role>
<security-role>
<role-name>manager</role-name>
</security-role>
</web-app>
就 Web 應用程式的設定部份,工作已經結束!但在將應用程式部署至伺服器時,得在伺服器上設定角色與使用者或群組的對應,設定的方式並非 Java EE 的標準,而是各伺服器而有所不同。例如在 Tomcat,可以在 conf/ tomcat-users.xml 中定義:
<?xml version='1.0' encoding='utf-8'?>
<tomcat-users>
<role rolename="manager"/>
<role rolename="admin"/>
<user username="caterpillar" password="123456" roles="admin,manager"/>
<user username="momor" password="654321" roles="manager "/>
</tomcat-users>
在這個設定中,caterpillar 同時具備有 admin 與 manager 角色,而 momor 則具備有 manager 角色。在啟動應用程式之後,如果存取 /admin 或 /manager,就 會出現對話方塊要求輸入名稱、密碼。如果輸入錯誤,就會被一直要求輸入正確的名稱、密碼。如果取消輸入,則會出現以下的畫面:
如果存取 /admin 下的頁面,只有輸入 caterpillar 名稱及正確的密碼,才可以正確觀看到頁面。如果存取 /admin 下的頁面,輸入了 momor 及正確密碼,雖然而可以通過驗證,但 momor 只有 manager 角色的權限,無法觀看 admin 角色才可以存取的頁面,所以會出現拒絕存取的畫面: