【JSP/SERVLET】Tomcat内置表单身份验证

一、概述

    前面是扯犊子的,JSP/SERVLET基于HTTP规范,提供了几种安全支持,BASIC、DIGEST、FORM、CLIENT-CERT,本文主要介绍一下FORM的安全支持开发,文末有一个小demo用于展示。

    因为FORM方式比较少用,因此本文介绍的原理点到即止,并没有特别特别深入,见谅。

    更多详情,请参见《JSP/SERVLET核心编程》(新浪微盘,您找PDF的天堂···)


二、详细

1. 原理简述

    FROM声明式安全基于表单验证。

    简述:用户想要访问某一个受保护的资源,如果用户未登路,则将用户导向一个特定格式的表单进行身份验证,验证通过则继续访问资源;验证不通过,则将用户导向一个提示页面。

    关键点:

    a. 对受保护资源进行配置。本例是基于URL进行限制保护,因此需要在web.xml中配置受保护的URL;

    b. 特定格式的表单写法。主要是三部分的固定写法,一是表单action必须为j_security_check,用户名输入input的name必须为j_username,用户密码的输入input的name必须为j_password;

    c. 只要用户登录成功,并且支持cookie(会话cookie,跟session搭一块干活的那个cookie:JSESSIONID),那么这个用户名和密码就会被保存到当前用户的session中,后续只要用户的会话cookie存在并且服务器session未过期,则一直验证通过,否则验证失败,更多原理,请往下看;

    FROM验证的安全性基于cookie/session机制的安全性,并且可以配置通过SSL传输,因此安全性还是比较高的,至少比BASIC的安全性高了不止一个等级。之前写的一个小demo,手动实现BASIC验证(不是基于JSP/SERVLET提供的封装了的BASIC,而是其底层原汁原味id实现):点击打开链接

    d. 局限性。用户的身份验证,是基于服务器提供的用户角色,以tomcat为例,所有基于FORM的用户安全验证,都是基于tomcat user的安全验证。也就是说,能够通过用户验证的用户配置,都是属于tomcat_dir/conf/tomcat-user.xml中的<role rolename="xxx"/>配置和<user username="ooo" password="ooo" roles="xxx"/>。因此,基于表单验证FORM的局限性在于程序的可移植性,尽管代码不需要重写,但是不同的服务器的用户规则不一样,因此需要重新配置用户;

2. demo讲解

    业务逻辑:首页index.jsp有一个超链,访问一个受保护的路径,如果用户未被验证,则自动跳转到认证页面,否则直接访问资源;如果认证失败,则自动跳转到一个失败提示页面。

    整个FORM验证的所有核心在于配置文件web.xml的配置,因此在理解demo业务逻辑的基础上,本节的所有内容将围绕配置文件展开。

2.1 首页

    即index.jsp,这个页面上有一个超链,用于访问受保护资源,内容如下所示。

<a href="${pageContext.request.contextPath}/gif">查看群相册</a>

2.2 配置文件

    此时,因为超链的访问路径“/gif”是受保护的,因此会判断用户是否已经验证通过,判断的条件是根据会话cookie找到对应的session,看session里面是否已经存在j_username和j_password。下面分别来讲解。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <display-name>春田花花同学会</display-name>
  <!-- 
  	一下配置都是基于FROM表单身份验证的角度来说明的
  	为了更好的阅读,请重下网上看配置文件,谢谢合作!
   -->
  <!-- 
  	和form-error-page不同的是,当在授权页面进行验证的时候,如果username是一个合法的认证用户
  	即username所在的role存在tomcat-users.xml中,但是这个role不具备访问该资源的权限,则会返回403,跳转到location指定的页面
  	而form-error-page是认证失败:1. 用户名或密码错误;2. username不存在tomcat-users.xml中
   -->
  <error-page>
    <error-code>403</error-code>
    <location>/security/fail.jsp</location>
  </error-page>
  <!-- 
  	login-config:
  		1. 当访问受限资源但是还未验证,则跳转到form-login-page页面,这个页面的编写需要固定的格式(理出为不变格式化的内容,其他可选自填),形如
  		<form action="j_security_check">
  			<input type="text" name="j_username"/>
  			<input type="password" name="j_password"/>
  		</form>
  		如果有密码,则表单最好是post提交
  		2. 当验证失败,即用户名和密码错误或用户不在授权列表中,则直接跳转到form-error-page指定页面
  			这个页面随便编写,目的是提示用户
   -->
  <login-config>
    <auth-method>FORM</auth-method>
    <form-login-config>
      <form-login-page>/security/login.jsp</form-login-page>
      <form-error-page>/security/logfail.jsp</form-error-page>
    </form-login-config>
  </login-config>
  <!-- 
  	security-role:对应着tomcat-users.xml中的role配置
  	可选,有无均可以,配置主要是方便项目开发的人查看
   -->
  <security-role>
    <role-name>user-auth</role-name>
  </security-role>
  <!-- 安全约束配置:
  		display-name:可选,表示受保护的资源名
  		web-resource-collection:必选,至少一个,配置受保护的资源
  								本处配置的受保护资源为:/gif
  		auth-constraint:授权约束,可选,role-name的value应该是在tomcat-users.xml中配置的<role rolename="xxx"/>
  						如果配置了auth-constraint,但是没有设置value,则表示任何人都不能访问
   -->
  <security-constraint>
    <display-name>R_file</display-name>
    <web-resource-collection>
      <web-resource-name>aiyou_gif</web-resource-name>
      <url-pattern>/gif</url-pattern>
    </web-resource-collection>
    <auth-constraint>
      <role-name>user-auth</role-name>
    </auth-constraint>
  </security-constraint>
  <!-- 首页,这个页面的超链请求到一个受保护的资源路径(/gif,即上文中security-constraint中配置),于是被拦截到一个登陆认证的页面 -->
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>

2.3 实现原理

    查看form-lgoin-page页面的请求头和响应头,推测j_username和j_password是保存于session中,但是查看sessionScope是空的,未能进一步验证。但是根据HTTP的迹象来推测,应该是介样的,有大神能进一步解答,请不吝赐教!

General
Remote Address:[::1]:8080
Request URL:http://localhost:8080/web02/j_security_check
Request Method:POST
Status Code:302 Found
Response Headers
HTTP/1.1 302 Found
Server: Apache-Coyote/1.1
Location: http://localhost:8080/web02/gif
Content-Length: 0
Date: Tue, 16 Jun 2015 09:54:39 GMT
Request Headers
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding:gzip, deflate
Accept-Language:zh-CN,zh;q=0.8
Cache-Control:max-age=0
Connection:keep-alive
Content-Length:36
Content-Type:application/x-www-form-urlencoded
Cookie:JSESSIONID=168CB17F9CF19F3615845B438332B7CD
Host:localhost:8080
Origin:http://localhost:8080
Referer:http://localhost:8080/web02/gif
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.81 Safari/537.36
Form Data
view parsed
j_username=wangxinyan&j_password=123
    随即验证通过,进行/gif的资源访问,此时会设置新的会话cookie,实际上在访问授权页面的时候,也会生成新的会话cookie。

General
Remote Address:[::1]:8080
Request URL:http://localhost:8080/web02/gif
Request Method:GET
Status Code:200 OK
Response Headers
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=6F12E8122EB68186270DC626974E24FE; Path=/web02/; HttpOnly
Cache-Control: private
Expires: Thu, 01 Jan 1970 08:00:00 CST
Content-Type: text/html;charset=UTF-8
Content-Length: 306
Date: Tue, 16 Jun 2015 09:54:39 GMT
Request Headers
GET /web02/gif HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.81 Safari/537.36
Referer: http://localhost:8080/web02/gif
Accept-Encoding: gzip, deflate, sdch
Accept-Language: zh-CN,zh;q=0.8
Cookie: JSESSIONID=168CB17F9CF19F3615845B438332B7CD

    基于Form的身份验证,是需要浏览器支持cookie,否则机制会瘫痪。但是整个验证的流程中HTTP透露的信息来看,并没有看到set-cookie除了会话cookie JSESSIONID之外的其他cookie,因此并不是将认证信息存放于cookie中;但是整个流程中都存在会话cookie,因此猜测FORM机制是将认证信息存放于session,每次访问cookie都会带着session id到浏览器,如果访问受保护资源,则浏览器通会过id找到session,session保存了认证信息,因此用户可以直接访问资源。

    并且,为了辅助验证,做了session.invalidate();的测试,发现当session失效以后,必须要重新验证才能访问受保护的资源,因此可以确定验证信息是借助于会话cookie/session机制来实现的,因此其安全性依赖于session和会话cookie的安全性,如果需要进一步提高安全性,在security-constraint中还可以配置SSL进行数据传输,因此,这种验证方式还是比较安全的!


三、demo下载

    示例demo百度云地址:点击打开链接

    (该demo仅用于展示原理,其中还有很多不完善的地方,仅仅能作为一个参考,谢谢!)


附注:

    参考资料:《JSP/SERVLET核心编程(第二版)》

    本文如有错漏,烦请不吝指正,谢谢!

发布了82 篇原创文章 · 获赞 95 · 访问量 22万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章