JSP - 安全
JavaServer Pages 和 servlet 为 Web 开发人员提供了多种机制来保护应用程序。通过在应用程序部署描述符中标识资源并为其分配角色,可以声明性地保护资源。
提供了多种级别的身份验证,从使用标识符和密码的基本身份验证,到使用证书的复杂身份验证。
基于角色的身份验证
servlet 规范中的身份验证机制使用一种称为 role-based security(基于角色的安全)技术。其思想不是在用户级别限制资源,而是创建角色并按角色限制资源。
您可以在位于 Tomcat 主目录下 conf 文件夹中的 tomcat-users.xml 文件中定义不同的角色。以下是该文件的一个示例 −
<?xml version = '1.0' encoding = 'utf-8'?> <tomcat-users> <role rolename = "tomcat"/> <role rolename = "role1"/> <role rolename = "manager"/> <role rolename = "admin"/> <user username = "tomcat" password = "tomcat" roles = "tomcat"/> <user username = "role1" password = "tomcat" roles = "role1"/> <user username = "both" password = "tomcat" roles = "tomcat,role1"/> <user username = "admin" password = "secret" roles = "admin,manager"/> </tomcat-users>
该文件定义了 username、password 和 role 之间的简单映射。请注意,一个用户可以具有多个角色;例如,username = "both" 同时属于 "tomcat" 角色和 "role1" 角色。
一旦您识别并定义了不同的角色,就可以通过 WEB-INF 目录中的 web.xml 文件使用 <security-constraint> 元素,对不同的 Web 应用程序资源施加基于角色的安全限制。
以下是 web.xml 中的一个示例条目 −
<web-app>
...
<security-constraint>
<web-resource-collection>
<web-resource-name>SecuredBookSite</web-resource-name>
<url-pattern>/secured/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<description>
Let only managers use this app
</description>
<role-name>manager</role-name>
</auth-constraint>
</security-constraint>
<security-role>
<role-name>manager</role-name>
</security-role>
<login-config>
<auth-method>BASIC</auth-method>
</login-config>
...
</web-app>
上述条目表示 −
任何匹配 /secured/* 的 URL 的 HTTP GET 或 POST 请求都将受到安全限制。
具有 manager 角色的用户被授予对受保护资源的访问权限。
login-config 元素用于描述 BASIC 形式的身份验证。
如果您尝试浏览任何包含 /security 目录的 URL,将显示以下对话框,要求输入用户名和密码。如果您提供用户 "admin" 和密码 "secret",则可以访问匹配 /secured/* 的 URL,因为我们已将用户 admin 定义为具有 manager 角色,该角色被允许访问此资源。
基于表单的认证
当你使用 FORM 认证方法时,必须提供一个登录表单来提示用户输入用户名和密码。以下是 login.jsp 的简单代码示例。这有助于创建用于同一目的的表单 −
<html>
<body bgcolor = "#ffffff">
<form method = "POST" action ="j_security_check">
<table border = "0">
<tr>
<td>Login</td>
<td><input type = "text" name="j_username"></td>
</tr>
<tr>
<td>Password</td>
<td><input type = "password" name="j_password"></td>
</tr>
</table>
<input type = "submit" value = "Login!">
</form>
</body>
</html>
这里你必须确保登录表单包含名为 j_username 和 j_password 的表单元素。<form> 标签中的 action 必须是 j_security_check。表单方法必须使用 POST。同时,你需要修改 <login-config> 标签,将 auth-method 指定为 FORM −
<web-app>
...
<security-constraint>
<web-resource-collection>
<web-resource-name>SecuredBookSite</web-resource-name>
<url-pattern>/secured/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<description>Let only managers use this app</description>
<role-name>manager</role-name>
</auth-constraint>
</security-constraint>
<security-role>
<role-name>manager</role-name>
</security-role>
<login-config>
<auth-method>FORM</auth-method>
<form-login-config>
<form-login-page>/login.jsp</form-login-page>
<form-error-page>/error.jsp</form-error-page>
</form-login-config>
</login-config>
...
</web-app>
现在,当你尝试访问任何带有 URL /secured/* 的资源时,它将显示上述表单,要求输入用户 ID 和密码。当容器看到 "j_security_check" action 时,它会使用某种内部机制来认证调用者。
如果登录成功且调用者被授权访问受保护资源,则容器会使用 session-id 从那时起为调用者标识一个登录会话。容器通过包含 session-id 的 cookie 来维护登录会话。服务器将 cookie 发送回客户端,只要调用者在后续请求中呈现此 cookie,容器就会知道调用者是谁。
如果登录失败,则服务器会发送由 form-error-page 设置标识的页面。
这里,j_security_check 是使用基于表单登录的应用程序必须为登录表单指定的 action。在同一表单中,你还应该有一个名为 j_username 的文本输入控件和一个名为 j_password 的 密码输入控件。当你看到这个时,它意味着表单中包含的信息将被提交到服务器,服务器将检查名称和密码。具体如何实现取决于服务器。
请查看 Standard Realm Implementations 以了解 j_security_check 在 Tomcat 容器中的工作原理。
Servlet/JSP 中的程序化安全
HttpServletRequest 对象提供了以下方法,这些方法可在运行时用于获取安全信息 −
| 序号 | 方法与描述 |
|---|---|
| 1 | String getAuthType() getAuthType() 方法返回一个 String 对象,该对象表示用于保护 Servlet 的认证方案名称。 |
| 2 | boolean isUserInRole(java.lang.String role) isUserInRole() 方法返回一个 boolean 值:如果用户在指定角色中则为 true,否则为 false。 |
| 3 | String getProtocol() getProtocol() 方法返回一个 String 对象,该对象表示用于发送请求的协议。可以检查此值来确定是否使用了安全协议。 |
| 4 | boolean isSecure() isSecure() 方法返回一个 boolean 值,表示请求是否使用 HTTPS 发出。true 表示使用 HTTPS 且连接安全,false 表示未使用。 |
| 5 | Principle getUserPrinciple() getUserPrinciple() 方法返回一个 java.security.Principle 对象,该对象包含当前已认证用户的名称。 |
例如,对于一个链接到经理页面的 JavaServer Page,您可能有以下代码 −
<% if (request.isUserInRole("manager")) { %>
<a href = "managers/mgrreport.jsp">Manager Report</a>
<a href = "managers/personnel.jsp">Personnel Records</a>
<% } %>
通过在 JSP 或 servlet 中检查用户的角色,您可以自定义网页,仅向用户显示其有权访问的项目。如果需要用户在认证表单中输入的用户名,您可以调用请求对象中的 getRemoteUser 方法。