宣告式基本驗證


如果打算讓 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 才可以使用 GETPOST 方法進行存取。請留意這個語義,這表示,除了 GETPOST 受約束外,其他 HTTP 方法是不受約束的,無論是否具備 admin 或 manager角色,都可以存取!

如果除了 GETPOST 之外,其他方法都要受到約束,除了使用 <http-method> 逐一列出 HEADPUT 等方法外,有個更方便的方式,就是使用 <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/>,那就沒有任何角色可以存取了。

例如,除了 GETPOST 之外,其他方法一律拒絕,可以這麼寫:

<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>

約束 GETPOST,然而拒絕其他 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 角色才可以存取的頁面,所以會出現拒絕存取的畫面:

宣告式基本驗證