Servlet处理表单重复提交and利用referer防盗链and实现request包含页面

还是让代码说话吧,我把这三个东西整合到一个Web Project里面了


首先是web.xml

<?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>FormServlet</servlet-name>
		<servlet-class>com.jadyer.servlet.FormServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>FormServlet</servlet-name>
		<url-pattern>/servlet/FormServlet</url-pattern>
	</servlet-mapping>
	
	<welcome-file-list>
		<welcome-file>form.jsp</welcome-file>
	</welcome-file-list>
</web-app>

然后是表单页面form.jsp

<%@ page language="java" pageEncoding="UTF-8"%>
<%@ page import="com.jadyer.util.DataCoderUtil"%>
<%
//生成表单令牌
session.setAttribute("myToken", DataCoderUtil.generateToken());
//request包含页面:也可以使用这种方式,把页面包含进来
//request.getRequestDispatcher("/form.jsp").include(request, response);
%>

<form action="<%=request.getContextPath()%>/servlet/FormServlet" method="POST">
	<input type="hidden" name="myToken" value="${myToken}">
	用户:<input type="text" name="username"><br/>
	密码:<input type="password" name="password"><br/>
	<input type="submit" value="提交">
</form>

下面是用于生成表单令牌的工具类DataCoderUtil.java

package com.jadyer.util;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Random;

import sun.misc.BASE64Encoder;

/**
 * DataCoderUtil
 * @see ========================================================================================
 * @see 这里的generateToken()是处理表单重复提交时,创建的表单令牌生成器,其返回经MD5和base64加密后的String
 * @see ========================================================================================
 * @see Java中每个数据都有一个摘要,即数据指纹。无论这个数据有多大,它的指纹都是固定的128位,即16个字节
 * @see 我们可以使用Java中提供的java.security.MessageDigest工具类,得到随机数的数据摘要,即数据指纹
 * @see ========================================================================================
 * @see 全新算法:base64编码
 * @see 任何数据经base64算法编码后,都会返回明文的字符串。该算法有一个特点:它会把每三个字节,都变成四个字节
 * @see 比如00110010.11001101.00101001会被变成00001100.00101100.00110100.00101001
 * @see 也就是把原来的24Bit平均分为四份,然后在每一份前面补两个零,以此凑成32Bit,即四个字节
 * @see 故,改变之后的四个字节,每个字节的最小值就是00000000,最大值就是00111111,即最小为零,最大为63
 * @see 所以,经过base64算法编码后,每个字节的最大值都不会超过64
 * @see 最后,base64算法会查询它自己定制的码表,该码表记录的是0--63所对应键盘上的明文字符,最后将其返回
 * @see ========================================================================================
 * @author 宏宇
 * @create Mar 6, 2012 2:38:04 AM
 */
public class DataCoderUtil {
	public static String generateToken() {
		String myToken = System.currentTimeMillis() + new Random().nextInt() + "";
		try {
			byte[] myTokenMD5 = MessageDigest.getInstance("md5").digest(myToken.getBytes()); //MD5算法加密
			return new BASE64Encoder().encode(myTokenMD5); //base64算法加密,最后返回
		} catch (NoSuchAlgorithmException e) {
			throw new RuntimeException(e);
		}
	}
}

最后是用于处理表单请求的FormServlet.java

package com.jadyer.servlet;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class FormServlet extends HttpServlet {
	private static final long serialVersionUID = -3435386674549645942L;

	public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		/**
		 * 利用referer防盗链
		 * @see 客户端访问时,只认可以http://127.0.0.1为首的URL
		 */
		String referer = request.getHeader("referer");
		if(null==referer || !referer.startsWith("http://127.0.0.1")){
			response.sendRedirect("/index.jsp");
			return; //如果没有这行代码,那么重定向之后,下面的代码仍会执行
		}
		
		/**
		 * 判断表单重复提交
		 * @see 思路:详见我的另一篇文章http://blog.csdn.net/jadyer/article/details/6174095
		 */
		if(!isTokenValid(request, response)){
			System.out.println("请不要重复提交表单...");
			return;
		}
		request.getSession().removeAttribute("myToken");
		System.out.println("向数据库中注册用户...");
	}
	
	/**
	 * 判断表单令牌是否有效
	 */
	private boolean isTokenValid(HttpServletRequest request, HttpServletResponse response){
		String client_token = request.getParameter("myToken");
		String server_token = (String)request.getSession().getAttribute("myToken");
		if(null == client_token){
			return false;
		}
		if(null == server_token){
			return false;
		}
		if(!client_token.equals(server_token)){
			return false;
		}
		return true;
	}
}

你可能感兴趣的:(算法,加密,servlet,String,server,token)