/** *模拟struts的令牌机制,写一个模拟的令牌类 */ package token; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; /** * 服务器放置表单重复提交 * @author Administrator * 单例 */ public class TokenProcessor { static final String TOKEN_KEY="web_submit_token"; private static TokenProcessor instance=new TokenProcessor(); /** * 最近一次生成令牌值的时间戳 */ private long previous; /** * getInstance() 方法得到单例类的实例 * @return */ public static TokenProcessor getInstance(){ return instance; } /** * 判断请求参数中的令牌值是否有效 */ public synchronized boolean isTokenValid(HttpServletRequest request){ //获取当前请求对应的session HttpSession session=request.getSession(false); if(null == session){ return false; } //从session中取出令牌值 String saved=(String) session.getAttribute(TOKEN_KEY); if(null == saved){ return false; } //清除session中的令牌值 resetToken(request); //得到请求参数中的令牌值 String token=(String) request.getParameter(TOKEN_KEY); if(null == token){ return false; } //当两者都不为null 就比较是否相等 return saved.equals(token); } /** * 清除session中的令牌值 */ public synchronized void resetToken(HttpServletRequest request){ HttpSession session=request.getSession(false); if(session == null){ return; } session.removeAttribute(TOKEN_KEY); } /** * 产生一个新的令牌值,保存到session中 * 如果当前session不存在,则创建一个session */ public synchronized void saveToken(HttpServletRequest request){ HttpSession session=request.getSession(); String token=generateToken(request); if(token != null){ session.setAttribute(TOKEN_KEY, token); } } /** * 从session中得到一个令牌值,如果session中 * 没有保存令牌值,就生成一个新的令牌值 */ public synchronized String getToken(HttpServletRequest request){ HttpSession session=request.getSession(false); if(null == session){ return null; } String token=(String) session.getAttribute(TOKEN_KEY); if(null == token){ token=generateToken(request); if(token != null){ session.setAttribute(TOKEN_KEY, token); return token; }else{ return null; } } return token; } /** * 根据会话的ID和当前的系统时间生成一个唯一的令牌 */ public synchronized String generateToken(HttpServletRequest request){ HttpSession session=request.getSession(); try{ byte[] id=session.getId().getBytes(); long current=System.currentTimeMillis(); if(current == previous){ current++; } previous = current; byte[] now = new Long(current).toString().getBytes(); MessageDigest md=MessageDigest.getInstance("MD5"); md.update(id); md.update(now); return toHex(md.digest()); }catch(NoSuchAlgorithmException e){ e.printStackTrace(); return null; } } /** * 将一个字节数组转换成一个十六进制的字符串 * @param digest * @return */ private String toHex(byte[] digest) { StringBuffer sb=new StringBuffer(digest.length*2); for(int i=0;i<digest.length;i++){ sb.append(Character.forDigit((digest[i] & 0xf0)>>4, 16)); sb.append(Character.forDigit(digest[i] & 0x0f, 16)); } return sb.toString(); } } /** *servlet中的使用 说明 */ package servlets; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import token.TokenProcessor; public class LoginServlet extends HttpServlet { int count = 0; @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=utf-8"); PrintWriter pw = response.getWriter(); String to=(String) request.getParameter("web_submit_token"); System.out.println("表单令牌:"+to); String old=(String) request.getSession().getAttribute("web_submit_token"); System.out.println("ses令牌:"+old); TokenProcessor processor = TokenProcessor.getInstance(); if (processor.isTokenValid(request)) { try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("submit:" + count); if (count % 2 == 1) { count = 0; } else { count++; } pw.println("SUCCESS"); }else{ processor.saveToken(request); pw.println("您已经提交了表单,不能重复提交!"); } pw.close(); } } /** *jsp 页面中的设置 */ <%@ page language="java" import="token.TokenProcessor" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www./TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>处理重复登录问题</title> <script type="text/javascript"> var checkSubmitFlg=true; function checkSubmit(){ /* if(checkSubmitFlg){ document.getElementById("fm").submit(); checkSubmitFlg=false; }else{ alert("您已经提交了表单,不能重复提交!"); } */ } </script> </head> <body> <%TokenProcessor processor=TokenProcessor.getInstance(); String token=processor.getToken(request); %> <form action="login" method="post" name="fm" id="fm"> <input type="hidden" name="web_submit_token" value=<%=token %> /> 用户名:<input type="text" name="name"/> 密码:<input type="password" name="pwd"/> <!-- <input type="button" value="提交" onclick="checkSubmit();"/> --> <input type="submit" value="sub"/> </form> </body> </html> /** *web.xml的配置 */ <?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java./xml/ns/javaee" xmlns:xsi="http://www./2001/XMLSchema-instance" xsi:schemaLocation="http://java./xml/ns/javaee http://java./xml/ns/javaee/web-app_2_5.xsd"> <display-name></display-name> <servlet> <servlet-name>LoginServlet</servlet-name> <servlet-class>servlets.LoginServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>LoginServlet</servlet-name> <url-pattern>/login</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app> |
|